{ "cells": [ { "cell_type": "markdown", "id": "b1627b66-f9c1-4c38-9e6c-dd25b8d8f92b", "metadata": {}, "source": [ "# Parsing PPM files\n", "To show how we can mix ASCII and binary data, we have an example where we parse Portable PixMap files (PPM). These files have a small ASCII header and the image itself in binary. The header looks something like this:\n", "\n", "```\n", "P6 # this marks the file type in the Netpbm family\n", "640 480\n", "256\n", "<>\n", "```" ] }, { "cell_type": "code", "execution_count": 1, "id": "dcf09929-f094-49b2-b18e-6600299c7086", "metadata": {}, "outputs": [], "source": [ "import numpy as np\n", "from dataclasses import dataclass\n", "from byteparsing import parse_bytes\n", "from byteparsing.parsers import (\n", " text_literal, integer, eol, named_sequence, sequence, construct,\n", " tokenize, item, array, fmap, text_end_by, optional)" ] }, { "cell_type": "markdown", "id": "d8a59c8c-f16b-4f16-9fec-4e64209758d9", "metadata": {}, "source": [ "The PPM header format allows for comments in the ASCII header." ] }, { "cell_type": "code", "execution_count": 2, "id": "2fdf9743-8e71-44a2-9f49-33fb9cbf8836", "metadata": {}, "outputs": [], "source": [ "comment = sequence(text_literal(\"#\"), text_end_by(\"\\n\"))" ] }, { "cell_type": "markdown", "id": "82ed35eb-6430-4001-9b9b-556b181e8351", "metadata": {}, "source": [ "We define a class that should contain all the data in the header." ] }, { "cell_type": "code", "execution_count": 3, "id": "dccd085c-0c97-48e2-a83f-85e03d2b5cfe", "metadata": {}, "outputs": [], "source": [ "@dataclass\n", "class Header:\n", " width: int\n", " height: int\n", " maxint: int" ] }, { "cell_type": "markdown", "id": "884baea7-e9ce-43f7-afd7-538428604e86", "metadata": {}, "source": [ "Then we can construct a parser for this header, using `named_sequence` and `construct`." ] }, { "cell_type": "code", "execution_count": 4, "id": "0ca943d4-c938-4bf2-8c78-2ad2711010c3", "metadata": {}, "outputs": [], "source": [ "header = named_sequence(\n", " _1 = tokenize(text_literal(\"P6\")),\n", " _2 = optional(comment),\n", " width = tokenize(integer),\n", " height = tokenize(integer),\n", " maxint = tokenize(integer)) >> construct(Header)" ] }, { "cell_type": "markdown", "id": "2616d26a-90c0-4c30-ad5f-c7f35f9a8b49", "metadata": {}, "source": [ "We'll have to pass on the header information to the parser for the binary blob somehow, so we define a function." ] }, { "cell_type": "code", "execution_count": 5, "id": "31099afb-aa54-4403-bd95-2710cecf2263", "metadata": {}, "outputs": [], "source": [ "def image_bytes(header: Header):\n", " shape = (header.height, header.width, 3)\n", " size = header.height * header.width * 3\n", " return array(np.uint8, size) >> fmap(lambda a: a.reshape(shape))\n", "\n", "ppm_image = header >> image_bytes" ] }, { "cell_type": "markdown", "id": "d2316576-b7ed-4e00-a129-5ed00e59b4ce", "metadata": {}, "source": [ "Let's test this on a sample image, and ignore the fact that `PIL` has a perfectly good parser for PPM files itself." ] }, { "cell_type": "code", "execution_count": 6, "id": "cfec76d7-e5e6-4ec9-9faf-180ab132efa3", "metadata": {}, "outputs": [ { "data": { "image/png": "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\n", "text/plain": [ "" ] }, "execution_count": 6, "metadata": {}, "output_type": "execute_result" } ], "source": [ "raw_data = open(\"python-logo.ppm\", \"rb\").read()\n", "image = parse_bytes(ppm_image, raw_data)\n", "\n", "from PIL import Image\n", "Image.frombytes(mode=\"RGB\", size=(image.shape[1], image.shape[0]), data=image)" ] } ], "metadata": { "kernelspec": { "display_name": "Python 3 (ipykernel)", "language": "python", "name": "python3" }, "language_info": { "codemirror_mode": { "name": "ipython", "version": 3 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", "version": "3.10.8" } }, "nbformat": 4, "nbformat_minor": 5 }