{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Cario example snippets with outputs\n",
    "Based on examples from lazka, stuaxo, fomightez and kolibril13"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {},
   "outputs": [],
   "source": [
    "import cairo\n",
    "from IPython.display import Image, display\n",
    "from math import pi\n",
    "from io import BytesIO\n",
    "\n",
    "def disp(draw_func):\n",
    "    surface = cairo.ImageSurface(cairo.FORMAT_ARGB32, 200, 200)\n",
    "    ctx = cairo.Context(surface)\n",
    "    draw_func(ctx, 200, 200)\n",
    "    with BytesIO() as fileobj:\n",
    "        surface.write_to_png(fileobj)\n",
    "        display(Image(fileobj.getvalue(), width=200))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "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\n",
      "text/plain": [
       "<IPython.core.display.Image object>"
      ]
     },
     "metadata": {
      "image/png": {
       "width": 200
      }
     },
     "output_type": "display_data"
    }
   ],
   "source": [
    "@disp\n",
    "def draw(cr, width, height):\n",
    "    cr.scale(width, height)\n",
    "    cr.set_line_width(0.04)\n",
    "\n",
    "    cr.arc(0.5, 0.5, 0.3, 0, 2 * pi)\n",
    "    cr.clip()\n",
    "\n",
    "    cr.rectangle(0, 0, 1, 1)\n",
    "    cr.fill()\n",
    "    cr.set_source_rgb(0, 1, 0)\n",
    "    cr.move_to(0, 0)\n",
    "    cr.line_to(1, 1)\n",
    "    cr.move_to(1, 0)\n",
    "    cr.line_to(0, 1)\n",
    "    cr.stroke()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "iVBORw0KGgoAAAANSUhEUgAAAMgAAADICAYAAACtWK6eAAAABmJLR0QA/wD/AP+gvaeTAAACuklEQVR4nO3cTWoUQRgG4FdN1DNozAG8hV5A8W/EU7jKGfw7RnCtK3d6Ad0oaDBGEH9WCmpcKIbExfSACGPrTFf1/DwPFISm5uPrxctUpasnAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgL4dTTJIcjfJVpJvzdhqrl1p5sDSuZhkJ8lBy3iV5EJPPUJ1R5LcSXsw/hy3kxzuoV+oapJwjMbNHvqFai5m8nCMxvnqXUMFRzPcT0wbkNexcWcBDTJ9OEbjcuXe6YhN5HhdLo3OdVgLZsLLdPcNslW5dyhuN90FZLdy73TEEquO/b4bYDICMt6HGa1FRQIy3pMOaz3usBYVCch49zqsdb/DWjATVpNsZ/oN+k48KGRBXcj0AfEMhIV2O5OH40YP/UJVh5Pcyv+H42bs8Vgi5/Nve5Lt/Puyai3JRpIHSd4k2WvGm+baRjMH5sJqhgcPN5O8yPAJ+W7z92aSS82cNuvN/L20B26vmbve4X3AzLqa5Ev+f8n2pfksLKzrGR47mXTTv9/UgIUzyHTh+D0kg8q9Q1EnknzO9OEYja9JTlW9AyhoM92FYzQ2q94BFLKe5Ge6D8jP+M9WcR5klTdIslKg7kqGv+RIQQJS3tk5rQ1VvE33y6vReFvxPpbSob4bWALfkxwrVPtHkuOFahNLrBoOCtb2rnthAlLex4K1PxWsTQSkhmcFaz8tWJsISA0P57Q2VOFBIbRw1AT+wmFFaOG4O7TwwhS08MottPCjDXPCWax+rSW5luRMktNJTjbX3yd5nuRRkrtJ3vXSHQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAATOgXPqoDzcCGeh0AAAAASUVORK5CYII=\n",
      "text/plain": [
       "<IPython.core.display.Image object>"
      ]
     },
     "metadata": {
      "image/png": {
       "width": 200
      }
     },
     "output_type": "display_data"
    }
   ],
   "source": [
    "@disp\n",
    "def draw(cr, width, height):\n",
    "    cr.scale(width, height) # eg1\n",
    "    cr.stroke()\n",
    "    cr.set_line_cap(cairo.LINE_CAP_ROUND)\n",
    "    cr.set_line_width(0.12)\n",
    "    cr.move_to(0.5, 0.5)\n",
    "    cr.line_to(0.5, 0.5)\n",
    "    \n",
    "    cr.stroke() #eg1\n",
    "    xc=.4\n",
    "    yc=.4\n",
    "    cr.arc(xc, yc, 0.05, 0, 2 * pi)\n",
    "    cr.fill()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "[encoded data, 8188 characters]\n",
      "text/plain": [
       "<IPython.core.display.Image object>"
      ]
     },
     "metadata": {
      "image/png": {
       "width": 200
      }
     },
     "output_type": "display_data"
    }
   ],
   "source": [
    "@disp\n",
    "def draw(cr, width, height):\n",
    "    cr.scale(width, height)\n",
    "    cr.set_line_width(0.04)\n",
    "\n",
    "    # a custom shape, that could be wrapped in a function\n",
    "    x0 = 0.1  # parameters like cairo_rectangle\n",
    "    y0 = 0.1\n",
    "    rect_width = 0.8\n",
    "    rect_height = 0.8\n",
    "    radius = 0.4  # and an approximate curvature radius\n",
    "\n",
    "    x1 = x0 + rect_width\n",
    "    y1 = y0 + rect_height\n",
    "\n",
    "    if rect_width / 2 < radius:\n",
    "        if rect_height / 2 < radius:\n",
    "            cr.move_to(x0, (y0 + y1) / 2)\n",
    "            cr.curve_to(x0, y0, x0, y0, (x0 + x1) / 2, y0)\n",
    "            cr.curve_to(x1, y0, x1, y0, x1, (y0 + y1) / 2)\n",
    "            cr.curve_to(x1, y1, x1, y1, (x1 + x0) / 2, y1)\n",
    "            cr.curve_to(x0, y1, x0, y1, x0, (y0 + y1) / 2)\n",
    "        else:\n",
    "            cr.move_to(x0, y0 + radius)\n",
    "            cr.curve_to(x0, y0, x0, y0, (x0 + x1) / 2, y0)\n",
    "            cr.curve_to(x1, y0, x1, y0, x1, y0 + radius)\n",
    "            cr.line_to(x1, y1 - radius)\n",
    "            cr.curve_to(x1, y1, x1, y1, (x1 + x0) / 2, y1)\n",
    "            cr.curve_to(x0, y1, x0, y1, x0, y1 - radius)\n",
    "    else:\n",
    "        if rect_height / 2 < radius:\n",
    "            cr.move_to(x0, (y0 + y1) / 2)\n",
    "            cr.curve_to(x0, y0, x0, y0, x0 + radius, y0)\n",
    "            cr.line_to(x1 - radius, y0)\n",
    "            cr.curve_to(x1, y0, x1, y0, x1, (y0 + y1) / 2)\n",
    "            cr.curve_to(x1, y1, x1, y1, x1 - radius, y1)\n",
    "            cr.line_to(x0 + radius, y1)\n",
    "            cr.curve_to(x0, y1, x0, y1, x0, (y0 + y1) / 2)\n",
    "        else:\n",
    "            cr.move_to(x0, y0 + radius)\n",
    "            cr.curve_to(x0, y0, x0, y0, x0 + radius, y0)\n",
    "            cr.line_to(x1 - radius, y0)\n",
    "            cr.curve_to(x1, y0, x1, y0, x1, y0 + radius)\n",
    "            cr.line_to(x1, y1 - radius)\n",
    "            cr.curve_to(x1, y1, x1, y1, x1 - radius, y1)\n",
    "            cr.line_to(x0 + radius, y1)\n",
    "            cr.curve_to(x0, y1, x0, y1, x0, y1 - radius)\n",
    "\n",
    "    cr.close_path()\n",
    "\n",
    "    cr.set_source_rgb(0.5, 0.5, 1)\n",
    "    cr.fill_preserve()\n",
    "    cr.set_source_rgba(0.5, 0, 0, 0.5)\n",
    "    cr.stroke()\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "[encoded data, 5552 characters]\n",
      "text/plain": [
       "<IPython.core.display.Image object>"
      ]
     },
     "metadata": {
      "image/png": {
       "width": 200
      }
     },
     "output_type": "display_data"
    }
   ],
   "source": [
    "@disp\n",
    "def draw(cr, width, height):\n",
    "    cr.scale(width, height)\n",
    "    cr.set_line_width(0.04)\n",
    "\n",
    "    x, y = 0.1, 0.5\n",
    "    x1, y1 = 0.4, 0.9\n",
    "    x2, y2 = 0.6, 0.1\n",
    "    x3, y3 = 0.9, 0.5\n",
    "\n",
    "    cr.move_to(x, y)\n",
    "    cr.curve_to(x1, y1, x2, y2, x3, y3)\n",
    "\n",
    "    cr.stroke()\n",
    "\n",
    "    cr.set_source_rgba(1, 0.2, 0.2, 0.6)\n",
    "    cr.set_line_width(0.03)\n",
    "    cr.move_to(x, y)\n",
    "    cr.line_to(x1, y1)\n",
    "    cr.move_to(x2, y2)\n",
    "    cr.line_to(x3, y3)\n",
    "    cr.stroke()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "[encoded data, 5544 characters]\n",
      "text/plain": [
       "<IPython.core.display.Image object>"
      ]
     },
     "metadata": {
      "image/png": {
       "width": 200
      }
     },
     "output_type": "display_data"
    }
   ],
   "source": [
    "def path_ellipse(cr, x, y, width, height, angle=0):\n",
    "    \"\"\"\n",
    "    x      - center x\n",
    "    y      - center y\n",
    "    width  - width of ellipse  (in x direction when angle=0)\n",
    "    height - height of ellipse (in y direction when angle=0)\n",
    "    angle  - angle in radians to rotate, clockwise\n",
    "    \"\"\"\n",
    "    cr.save()\n",
    "    cr.translate(x, y)\n",
    "    cr.rotate(angle)\n",
    "    cr.scale(width / 2.0, height / 2.0)\n",
    "    cr.arc(0.0, 0.0, 1.0, 0.0, 2.0 * pi)\n",
    "    cr.restore()\n",
    "\n",
    "@disp\n",
    "def draw(cr, width, height):\n",
    "    cr.scale(width, height)\n",
    "    cr.set_line_width(0.04)\n",
    "\n",
    "    path_ellipse(cr, 0.5, 0.5, 1.0, 0.3, pi / 4.0)\n",
    "\n",
    "    # fill\n",
    "    cr.set_source_rgba(1, 0, 0, 1)\n",
    "    cr.fill_preserve()\n",
    "\n",
    "    # stroke\n",
    "    # reset identity matrix so line_width is a constant\n",
    "    # width in device-space, not user-space\n",
    "    cr.save()\n",
    "    cr.identity_matrix()\n",
    "    cr.set_source_rgba(0, 0, 0, 1)\n",
    "    cr.set_line_width(3)\n",
    "    cr.stroke()\n",
    "    cr.restore()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "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\n",
      "text/plain": [
       "<IPython.core.display.Image object>"
      ]
     },
     "metadata": {
      "image/png": {
       "width": 200
      }
     },
     "output_type": "display_data"
    }
   ],
   "source": [
    "@disp\n",
    "def draw(cr, width, height):\n",
    "    cr.scale(width, height)\n",
    "    cr.set_line_width(0.04)\n",
    "\n",
    "    cr.move_to(0.5, 0.1)\n",
    "    cr.line_to(0.9, 0.9)\n",
    "    cr.rel_line_to(-0.4, 0.0)\n",
    "    cr.curve_to(0.2, 0.9, 0.2, 0.5, 0.5, 0.5)\n",
    "    cr.close_path()\n",
    "\n",
    "    cr.set_source_rgb(0, 0, 1)\n",
    "    cr.fill_preserve()\n",
    "    cr.set_source_rgb(0, 0, 0)\n",
    "    cr.stroke()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "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\n",
      "text/plain": [
       "<IPython.core.display.Image object>"
      ]
     },
     "metadata": {
      "image/png": {
       "width": 200
      }
     },
     "output_type": "display_data"
    }
   ],
   "source": [
    "@disp\n",
    "def draw(cr, width, height):\n",
    "    cr.scale(width, height)\n",
    "    cr.set_line_width(0.04)\n",
    "\n",
    "    cr.move_to(0.5, 0.1)\n",
    "    cr.line_to(0.9, 0.9)\n",
    "    cr.rel_line_to(-0.4, 0.0)\n",
    "    cr.curve_to(0.2, 0.9, 0.2, 0.5, 0.5, 0.5)\n",
    "    cr.close_path()\n",
    "\n",
    "    cr.move_to(0.25, 0.1)\n",
    "    cr.rel_line_to(0.2, 0.2)\n",
    "    cr.rel_line_to(-0.2, 0.2)\n",
    "    cr.rel_line_to(-0.2, -0.2)\n",
    "    cr.close_path()\n",
    "\n",
    "    cr.set_source_rgb(0, 0, 1)\n",
    "    cr.fill_preserve()\n",
    "    cr.set_source_rgb(0, 0, 0)\n",
    "    cr.stroke()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "[encoded data, 7324 characters]\n",
      "text/plain": [
       "<IPython.core.display.Image object>"
      ]
     },
     "metadata": {
      "image/png": {
       "width": 200
      }
     },
     "output_type": "display_data"
    }
   ],
   "source": [
    "@disp\n",
    "def draw(cr, width, height):\n",
    "    cr.scale(width, height)\n",
    "    cr.set_line_width(0.04)\n",
    "\n",
    "    pat = cairo.LinearGradient(0.0, 0.0, 0.0, 1.0)\n",
    "    pat.add_color_stop_rgba(1, 0, 0, 0, 1)\n",
    "    pat.add_color_stop_rgba(0, 1, 1, 1, 1)\n",
    "    cr.rectangle(0, 0, 1, 1)\n",
    "    cr.set_source(pat)\n",
    "    cr.fill()\n",
    "\n",
    "    pat = cairo.RadialGradient(0.45, 0.4, 0.1,\n",
    "                               0.4, 0.4, 0.5)\n",
    "    pat.add_color_stop_rgba(0, 1, 1, 1, 1)\n",
    "    pat.add_color_stop_rgba(1, 0, 0, 0, 1)\n",
    "    cr.set_source(pat)\n",
    "    cr.arc(0.5, 0.5, 0.3, 0, 2 * pi)\n",
    "    cr.fill()\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "[encoded data, 21128 characters]\n",
      "text/plain": [
       "<IPython.core.display.Image object>"
      ]
     },
     "metadata": {
      "image/png": {
       "width": 200
      }
     },
     "output_type": "display_data"
    }
   ],
   "source": [
    "@disp\n",
    "def draw(cr, width, height):\n",
    "    cr.scale(width, height)\n",
    "    cr.set_line_width(0.04)\n",
    "\n",
    "    pattern = cairo.LinearGradient(0, 0, 1, 1)\n",
    "    pattern.add_color_stop_rgb(0, 0, 0.3, 0.8)\n",
    "    pattern.add_color_stop_rgb(1, 0, 0.8, 0.3)\n",
    "\n",
    "    mask = cairo.RadialGradient(0.5, 0.5, 0.25, 0.5, 0.5, 0.5)\n",
    "    mask.add_color_stop_rgba(0, 0, 0, 0, 1)\n",
    "    mask.add_color_stop_rgba(0.5, 0, 0, 0, 0)\n",
    "\n",
    "    cr.set_source(pattern)\n",
    "    cr.mask(mask)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "iVBORw0KGgoAAAANSUhEUgAAAMgAAADICAYAAACtWK6eAAAABmJLR0QA/wD/AP+gvaeTAAACLElEQVR4nO3dwW2DUBBAQRO5JAqkjVATPTkNkCclxv4kzBw5rPbA00pcuN0AAAAAAAAAAAAAAAAAAABg33T0wG3bHkfP5DzmeT78nTmzj9ELwJkJBIJAIAgEgkAgCASCQCAIBIJAIAgEgkAgCASCQCAIBIJAIAgEgkAgCASCQCAIBIJAIAgEgkAgCASCQCAIBIJAIAgEgkAgCASCQCAIBIJAIAgEgkAgCATCffQC77Cu6+gV/pNl9AI/sDw7wAWBIBAIAoEgEAgCgXCJr1jfWUYv8Ad9jl5gx/TC2S4IBIFAEAgEgUAQCASBQBAIBIFAEAgEgUAQCASBQBAIBIFAEAgEgUAQCASBQBAIBIFAEAgEgUAQCASBQBAIBIFAEAgEgUAQCASBQBAIBIFAEAgEgUAQCASBQBAIBIFAEAgEgUAQCASBQBAIBIFAEAgEgUAQCASBQBAIBIFAEAgEgUAQCASBQBAIBIFAEAgEgUAQCASBQBAIBIFAEAgEgUAQCASBQBAIBIFAEAgEgUAQCASBQBAIBIFAEAgEgUCYRi/wJsvew8ebl+A14iVenp3tgkAQCASBQBAIBIFAEAgEgUAQCASBQBAIBIFAEAgEgUAQCASBQBAIBIFAEAgEgUAQCASBQBAIBIFAEAgEgUAQCASBQBAIBIFAEAgEgUAQCASBQBAIBIFAEAiE++gFRrrKH0z5PRcEgkAgCASCQCAIBAAAAAAAAAAAAAAAAACu4AvVCgs0Of7NigAAAABJRU5ErkJggg==\n",
      "text/plain": [
       "<IPython.core.display.Image object>"
      ]
     },
     "metadata": {
      "image/png": {
       "width": 200
      }
     },
     "output_type": "display_data"
    }
   ],
   "source": [
    "@disp\n",
    "def draw(cr, width, height):\n",
    "    cr.scale(width, height)\n",
    "    cr.set_line_width(0.04)\n",
    "\n",
    "    cr.rectangle(0.1, 0.1, 0.6, 0.6)\n",
    "    cr.set_line_width(0.03)\n",
    "    cr.set_source_rgb(0.8, 0.8, 0.8)\n",
    "    cr.fill()\n",
    "\n",
    "    cr.push_group()\n",
    "    cr.rectangle(0.3, 0.3, 0.6, 0.6)\n",
    "    cr.set_source(cairo.SolidPattern(1, 0, 0))\n",
    "    cr.fill_preserve()\n",
    "    cr.set_source(cairo.SolidPattern(0, 0, 0))\n",
    "    cr.stroke()\n",
    "    cr.pop_group_to_source()\n",
    "    cr.paint_with_alpha(0.5)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "[encoded data, 30480 characters]\n",
      "text/plain": [
       "<IPython.core.display.Image object>"
      ]
     },
     "metadata": {
      "image/png": {
       "width": 200
      }
     },
     "output_type": "display_data"
    }
   ],
   "source": [
    "@disp\n",
    "def draw(ctx, width, height):\n",
    "    LINES = 32\n",
    "    MAX_THETA = .80 * pi * 2\n",
    "    THETA_INC = 2.0 * MAX_THETA / (LINES - 1)\n",
    "\n",
    "    ctx.set_source_rgb(0, 0, 0)\n",
    "    ctx.set_line_width(2.0)\n",
    "\n",
    "    ctx.save()\n",
    "\n",
    "    ctx.translate(width / 2, height / 2)\n",
    "    ctx.rotate(MAX_THETA)\n",
    "\n",
    "    for i in range(LINES):\n",
    "        ctx.move_to(-2 * width, 0)\n",
    "        ctx.line_to(2 * width, 0)\n",
    "        ctx.stroke()\n",
    "\n",
    "        ctx.rotate(- THETA_INC)\n",
    "\n",
    "    ctx.restore()\n",
    "\n",
    "    ctx.set_line_width(6)\n",
    "    ctx.set_source_rgb(1, 0, 0)\n",
    "\n",
    "    ctx.move_to(width / 4.0, 0)\n",
    "    ctx.rel_line_to(0, height)\n",
    "    ctx.stroke()\n",
    "\n",
    "    ctx.move_to(3 * width / 4.0, 0)\n",
    "    ctx.rel_line_to(0, height)\n",
    "    ctx.stroke()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 13,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "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\n",
      "text/plain": [
       "<IPython.core.display.Image object>"
      ]
     },
     "metadata": {
      "image/png": {
       "width": 200
      }
     },
     "output_type": "display_data"
    }
   ],
   "source": [
    "@disp\n",
    "def draw(cr, width, height):\n",
    "    cr.scale(width, height)\n",
    "    cr.set_line_width(0.04)\n",
    "\n",
    "    cr.move_to(0.5, 0.1)\n",
    "    cr.line_to(0.9, 0.9)\n",
    "    cr.rel_line_to(-0.4, 0.0)\n",
    "    cr.curve_to(0.2, 0.9, 0.2, 0.5, 0.5, 0.5)\n",
    "\n",
    "    cr.stroke()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 14,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "iVBORw0KGgoAAAANSUhEUgAAAMgAAADICAYAAACtWK6eAAAABmJLR0QA/wD/AP+gvaeTAAADcklEQVR4nO3aTW4UVxiF4ePIUlgDP70AlIy8ArIIjFgFi2qxjLACTxKJDQBzzCQgW+4MXElAio7dP7e6oZ9HqolV9ele+b5SddsJAAAAAAAAAAAAAAAAAAAAAAAAAAAAHJeTfS/gyD1O8jLJsyRPkzyafv4hydskb5K8TvJ+L6v71mrwfGeRfy2SLJNc5/bgtet6unexl5X+5651bntBkuRFksusf4Aup2f3RSAM9yrJTTY/RDfTjH0QCEOdZ7s4vo7kfOa1Z4v1CoQ7PUzyMbs7TJ+SPJl1BwJhoGV2f6CWs+5AIAyySHKV3R+oq8z7zdZRBvLTvhdwBM6TnA6Ye5rk+YC5fEUg4/32nc4mApnDLwNn/zpwNvlB/ry/OjtbJcnJxcUh7udzkp/vc+Pq7CxJcnJxcd/ZX5I82GhV67v354QN9pEc6Fkc8W68K5t8cFvnmbl+IfeK4wBnE69YUAkECoFAIRAoBAKFQKAQCBQCgUIgUAgECoFAIRAoBAKFQKAQCBQCgUIgUAgECoFAIRAoBAKFQKAQCBQCgUIgUAgECoFAIRAoBAKFQKAQCBQCgUIgUAgECoFAIRAoBAKFQKAQCBQCgUIgUAgECoFAIRAoBAKFQKAQCBQCgUIgUAgECoFAIRAoBAKFQKAQCBQCgUIgUAgECoFAIRAoBAKFQKAQCBQCgUIgUAgECoFAIRAoBAKFQKAQCBQCgUIgUAgECoFAIRAoBAKFQKAQCBQCgUIgUAgECoFAIRAoBAKFQKAQCBQCgUIgUAgECoFAIRAoBAKFQKAQCBQCgUIgUAgECoFAIRAoBAKFQKAQCBQCgUIgUAgECoFAIRAoBAKFQKAQCBQCgUIgUAgECoFAIRAoBAKFQKAQCBSn+15AcbLGvasNnpnL5yQPBs3+a9BcmM273AY84no34z5G7eGf6yB5xRrvz4Gz/xg4mwhkDr9/p7NhFoskV9n9K8nVNHsuR/mKxTyW2f2BWs66A4Ew0MMkH7O7w/QpyZNZdyAQBjtPcpPtD9LNNGtuAmG4V9kukptpxj4IhFm8SHKZ9Q/Q5fTsvgiE2Sxy+yH7OncfnOvp3jm/sfo/RxnIIf5rxjF5nORlkmdJniZ5NP38Q5K3Sd4keZ3k/V5W963Rh9hZBAAAAAAAAAAAAAAAAAAAAAAAAAAAgAPwN+bOm5itb3PKAAAAAElFTkSuQmCC\n",
      "text/plain": [
       "<IPython.core.display.Image object>"
      ]
     },
     "metadata": {
      "image/png": {
       "width": 200
      }
     },
     "output_type": "display_data"
    }
   ],
   "source": [
    "@disp\n",
    "def draw(cr, width, height):\n",
    "    cr.scale(width, height)\n",
    "    cr.set_line_width(0.04)\n",
    "\n",
    "    cr.set_line_width(0.12)\n",
    "    cr.set_line_cap(cairo.LINE_CAP_BUTT)  # default\n",
    "    cr.move_to(0.25, 0.2)\n",
    "    cr.line_to(0.25, 0.8)\n",
    "    cr.stroke()\n",
    "    cr.set_line_cap(cairo.LINE_CAP_ROUND)\n",
    "    cr.move_to(0.5, 0.2)\n",
    "    cr.line_to(0.5, 0.8)\n",
    "    cr.stroke()\n",
    "    cr.set_line_cap(cairo.LINE_CAP_SQUARE)\n",
    "    cr.move_to(0.75, 0.2)\n",
    "    cr.line_to(0.75, 0.8)\n",
    "    cr.stroke()\n",
    "\n",
    "    # draw helping lines\n",
    "    cr.set_source_rgb(1, 0.2, 0.2)\n",
    "    cr.set_line_width(0.01)\n",
    "    cr.move_to(0.25, 0.2)\n",
    "    cr.line_to(0.25, 0.8)\n",
    "    cr.move_to(0.5, 0.2)\n",
    "    cr.line_to(0.5, 0.8)\n",
    "    cr.move_to(0.75, 0.2)\n",
    "    cr.line_to(0.75, 0.8)\n",
    "    cr.stroke()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 15,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "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\n",
      "text/plain": [
       "<IPython.core.display.Image object>"
      ]
     },
     "metadata": {
      "image/png": {
       "width": 200
      }
     },
     "output_type": "display_data"
    }
   ],
   "source": [
    "@disp\n",
    "def draw(cr, width, height):\n",
    "    cr.scale(width, height)\n",
    "    cr.set_line_width(0.04)\n",
    "\n",
    "    cr.set_line_width(0.16)\n",
    "    cr.move_to(0.3, 0.33)\n",
    "    cr.rel_line_to(0.2, -0.2)\n",
    "    cr.rel_line_to(0.2, 0.2)\n",
    "    cr.set_line_join(cairo.LINE_JOIN_MITER)  # default\n",
    "    cr.stroke()\n",
    "\n",
    "    cr.move_to(0.3, 0.63)\n",
    "    cr.rel_line_to(0.2, -0.2)\n",
    "    cr.rel_line_to(0.2, 0.2)\n",
    "    cr.set_line_join(cairo.LINE_JOIN_BEVEL)\n",
    "    cr.stroke()\n",
    "\n",
    "    cr.move_to(0.3, 0.93)\n",
    "    cr.rel_line_to(0.2, -0.2)\n",
    "    cr.rel_line_to(0.2, 0.2)\n",
    "    cr.set_line_join(cairo.LINE_JOIN_ROUND)\n",
    "    cr.stroke()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 16,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "[encoded data, 13216 characters]\n",
      "text/plain": [
       "<IPython.core.display.Image object>"
      ]
     },
     "metadata": {
      "image/png": {
       "width": 200
      }
     },
     "output_type": "display_data"
    }
   ],
   "source": [
    "@disp\n",
    "def draw(cr, width, height):\n",
    "    cr.scale(width, height)\n",
    "    cr.set_line_width(0.04)\n",
    "\n",
    "    cr.select_font_face(\"Sans\", cairo.FONT_SLANT_NORMAL,\n",
    "                        cairo.FONT_WEIGHT_NORMAL)\n",
    "    # draw 0.08 glyphs in 0.10 squares, at(0.01, 0.02) from left corner\n",
    "    cr.set_font_size(0.08)\n",
    "\n",
    "    glyphs = []\n",
    "    index = 0\n",
    "    for y in range(10):\n",
    "        for x in range(10):\n",
    "            glyphs.append((index, x / 10.0 + 0.01, y / 10.0 + 0.08))\n",
    "            index += 1\n",
    "\n",
    "    cr.show_glyphs(glyphs)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 17,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "[encoded data, 23652 characters]\n",
      "text/plain": [
       "<IPython.core.display.Image object>"
      ]
     },
     "metadata": {
      "image/png": {
       "width": 200
      }
     },
     "output_type": "display_data"
    }
   ],
   "source": [
    "@disp\n",
    "def draw(cr, width, height):\n",
    "    cr.scale(width, height)\n",
    "    cr.set_line_width(0.04)\n",
    "\n",
    "    cr.select_font_face(\"Sans\", cairo.FONT_SLANT_NORMAL,\n",
    "                        cairo.FONT_WEIGHT_NORMAL)\n",
    "    # draw 0.16 glyphs in 0.20 squares, at (0.02, 0.04) from left corner\n",
    "    cr.set_font_size(0.16)\n",
    "\n",
    "    glyphs = []\n",
    "    index = 20\n",
    "    for y in range(5):\n",
    "        for x in range(5):\n",
    "            glyphs.append((index, x / 5.0 + 0.02, y / 5.0 + 0.16))\n",
    "            index += 1\n",
    "\n",
    "    cr.glyph_path(glyphs)\n",
    "    cr.set_source_rgb(0.5, 0.5, 1.0)\n",
    "    cr.fill_preserve()\n",
    "    cr.set_source_rgb(0, 0, 0)\n",
    "    cr.set_line_width(0.005)\n",
    "    cr.stroke()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 18,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "iVBORw0KGgoAAAANSUhEUgAAAMgAAADICAYAAACtWK6eAAAABmJLR0QA/wD/AP+gvaeTAAAD+ElEQVR4nO3XSXIbQQxFQdKh+1+ZXsiQbJP6nLq7psyNFFz1BniF8+l0uZyAP87nz7+fc/Gr5adA7z6+/63JgRXdfkkpCAQf1z+5SVhJfjkpCAQ3ClLcJMzssZeSgkAQClLcJMzkuZeRgkDwQEGKm4SRvfYSUhAInihIcZMwkvdePgoCwQsFKW4SerbNS0dBIHijIMVNQk+2fdkoCAQbFKS4SWhpn5eMgkCwYUGKm4Qj7ftyURAIdihIcZOwp2NeKgoCwY4FKW4StnTsy0RBIDigIMVNwjvavEQUBIIDC1LcJDyj7ctDQSBoUJDiJiHp46WhIBA0LEjpY1PQi75eFgoCQQcFKX1tDo7W50tCQSDoqCClz03CXvp+OSgIBB0WpPS9WXjXGC8FBYGg44KUMTYNjxrrZaAgEAxQkDLW5uF/Y74EFASCgQpSxtxE6xq7/AoCwYAFKWNvpvnNUXoFgWDggpQ5NtU85iq7gkAwQUHKXJtrPHOWXEEgmKggZc5N1q+5y60gEExYkDL3ZmtvjVIrCAQTF6SssemOs1aZFQSCBQpS1tp821uzxAoCwUIFKWtuwtetXV4FgWDBgpS1N+N9Sns6KQhECxek2JT/Uta/KQgECvJl9c2ppLcoCAQKcmW1Tbp6OTMFgUBBfjT7Zl2tlK9REAgU5K7ZNu3sZdyWgkCgIA8bffPOVsJjKAgECvK0kTbx6NVrT0EgUJCX2c4rUBAIDAgEBgQCAwKBAYHAgEBgQCAwIBAYEAgMCAQGBAIDAoEBgcCAQGBAIDAgEBgQCAwIBAYEAgMCgQGBwIBAYEAgMCAQGBAIDAgEBgQCAwKBAYHAgEBgQCAwIBAYEAgMCAQGBAIDAoEBgcCAQGBAIDAgEBgQCAwIBAYEgo/WHzCuy6X1F7A/BYFAQZ52Prf+Ao6jIBAoyMPcHCtSEAgU5C43x8oUBAIF+ZGbAwWBSEGuuDn4piAQKMgXNwfXFAQCBXFzECgIBAsXxM3BfQoCwYIFcXPwOAWBYKGCuDl4noJAsEBB3By8TkEgmLggbg7epyAQTFgQNwfbURAIJiqIm4PtKQgEExTEzcF+FASCgQvi5mB/CgLBgAVxc3AcBYFgoIK4OTiegkAwQEHcHLSjIBB0XBA3B+0pCAQdFsTNQT8UBIKOCuLmoD8KAkEHBXFz0C8FgaBhQdwc9E9BIGhQEDcH41AQCA4siJuD8SgIBAcUxM3BuBQEgh0L4uZgfAoCwQ4FcXMwDwWBYMOCuDmYj4JAsEFB3BzMS0EgeKMgbg7mpyAQvFAQNwfrUBAIniiIm4P1KAgEDxTEzcG6FASCUBA3BygIBDcK4uaAoiAQnN0a8DMFgeA3/9h6J1+cU/4AAAAASUVORK5CYII=\n",
      "text/plain": [
       "<IPython.core.display.Image object>"
      ]
     },
     "metadata": {
      "image/png": {
       "width": 200
      }
     },
     "output_type": "display_data"
    }
   ],
   "source": [
    "@disp\n",
    "def draw(ctx, width, height):\n",
    "    wd = .02 * width\n",
    "    hd = .02 * height\n",
    "\n",
    "    width -= 2\n",
    "    height -= 2\n",
    "\n",
    "    ctx.move_to(width + 1, 1 - hd)\n",
    "    for i in range(20):\n",
    "        ctx.rel_line_to(0, height - hd * (2 * i - 1))\n",
    "        ctx.rel_line_to(-(width - wd * (2 * i)), 0)\n",
    "        ctx.rel_line_to(0, -(height - hd * (2 * i)))\n",
    "        ctx.rel_line_to(width - wd * (2 * i + 1), 0)\n",
    "\n",
    "    ctx.set_source_rgb(0, 0, 1)\n",
    "    ctx.stroke()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 19,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "[encoded data, 8080 characters]\n",
      "text/plain": [
       "<IPython.core.display.Image object>"
      ]
     },
     "metadata": {
      "image/png": {
       "width": 200
      }
     },
     "output_type": "display_data"
    }
   ],
   "source": [
    "@disp\n",
    "def draw(cr, width, height):\n",
    "    cr.scale(width, height)\n",
    "    cr.set_line_width(0.04)\n",
    "\n",
    "    cr.select_font_face(\"Sans\", cairo.FONT_SLANT_NORMAL,\n",
    "                        cairo.FONT_WEIGHT_BOLD)\n",
    "    cr.set_font_size(0.35)\n",
    "\n",
    "    cr.move_to(0.04, 0.53)\n",
    "    cr.show_text(\"Hello\")\n",
    "\n",
    "    cr.move_to(0.27, 0.65)\n",
    "    cr.text_path(\"void\")\n",
    "    cr.set_source_rgb(0.5, 0.5, 1)\n",
    "    cr.fill_preserve()\n",
    "    cr.set_source_rgb(0, 0, 0)\n",
    "    cr.set_line_width(0.01)\n",
    "    cr.stroke()\n",
    "\n",
    "    # draw helping lines\n",
    "    cr.set_source_rgba(1, 0.2, 0.2, 0.6)\n",
    "    cr.arc(0.04, 0.53, 0.02, 0, 2 * pi)\n",
    "    cr.arc(0.27, 0.65, 0.02, 0, 2 * pi)\n",
    "    cr.fill()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 20,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "[encoded data, 4300 characters]\n",
      "text/plain": [
       "<IPython.core.display.Image object>"
      ]
     },
     "metadata": {
      "image/png": {
       "width": 200
      }
     },
     "output_type": "display_data"
    }
   ],
   "source": [
    "@disp\n",
    "def draw(cr, width, height):\n",
    "    cr.scale(width, height)\n",
    "    cr.set_line_width(0.04)\n",
    "\n",
    "    utf8 = \"cairo\"\n",
    "\n",
    "    cr.select_font_face(\"Sans\",\n",
    "                        cairo.FONT_SLANT_NORMAL,\n",
    "                        cairo.FONT_WEIGHT_NORMAL)\n",
    "\n",
    "    cr.set_font_size(0.2)\n",
    "    x_bearing, y_bearing, width, height, x_advance, y_advance = \\\n",
    "        cr.text_extents(utf8)\n",
    "    x = 0.5 - (width / 2 + x_bearing)\n",
    "    y = 0.5 - (height / 2 + y_bearing)\n",
    "\n",
    "    cr.move_to(x, y)\n",
    "    cr.show_text(utf8)\n",
    "\n",
    "    # draw helping lines\n",
    "    cr.set_source_rgba(1, 0.2, 0.2, 0.6)\n",
    "    cr.arc(x, y, 0.05, 0, 2 * pi)\n",
    "    cr.fill()\n",
    "    cr.move_to(0.5, 0)\n",
    "    cr.rel_line_to(0, 1)\n",
    "    cr.move_to(0, 0.5)\n",
    "    cr.rel_line_to(1, 0)\n",
    "    cr.stroke()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 21,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "[encoded data, 4552 characters]\n",
      "text/plain": [
       "<IPython.core.display.Image object>"
      ]
     },
     "metadata": {
      "image/png": {
       "width": 200
      }
     },
     "output_type": "display_data"
    }
   ],
   "source": [
    "@disp\n",
    "def draw(cr, width, height):\n",
    "    cr.scale(width, height)\n",
    "    cr.set_line_width(0.04)\n",
    "\n",
    "    utf8 = \"cairo\"\n",
    "\n",
    "    cr.select_font_face(\"Sans\",\n",
    "                        cairo.FONT_SLANT_NORMAL,\n",
    "                        cairo.FONT_WEIGHT_NORMAL)\n",
    "\n",
    "    cr.set_font_size(0.4)\n",
    "    x_bearing, y_bearing, width, height, x_advance, y_advance = \\\n",
    "        cr.text_extents(utf8)\n",
    "\n",
    "    x = 0.1\n",
    "    y = 0.6\n",
    "\n",
    "    cr.move_to(x, y)\n",
    "    cr.show_text(utf8)\n",
    "\n",
    "    # draw helping lines\n",
    "    cr.set_source_rgba(1, 0.2, 0.2, 0.6)\n",
    "    cr.arc(x, y, 0.05, 0, 2 * pi)\n",
    "    cr.fill()\n",
    "    cr.move_to(x, y)\n",
    "    cr.rel_line_to(0, -height)\n",
    "    cr.rel_line_to(width, 0)\n",
    "    cr.rel_line_to(x_bearing, -y_bearing)\n",
    "    cr.stroke()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 22,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "[encoded data, 26104 characters]\n",
      "text/plain": [
       "<IPython.core.display.Image object>"
      ]
     },
     "metadata": {
      "image/png": {
       "width": 200
      }
     },
     "output_type": "display_data"
    }
   ],
   "source": [
    "import math\n",
    "all_width = all_height = text_width = 0\n",
    "\n",
    "def warpPath(ctx, function):\n",
    "    first = True\n",
    "\n",
    "    for type, points in ctx.copy_path():\n",
    "        if type == cairo.PATH_MOVE_TO:\n",
    "            if first:\n",
    "                ctx.new_path()\n",
    "                first = False\n",
    "            x, y = function(*points)\n",
    "            ctx.move_to(x, y)\n",
    "\n",
    "        elif type == cairo.PATH_LINE_TO:\n",
    "            x, y = function(*points)\n",
    "            ctx.line_to(x, y)\n",
    "\n",
    "        elif type == cairo.PATH_CURVE_TO:\n",
    "            x1, y1, x2, y2, x3, y3 = points\n",
    "            x1, y1 = function(x1, y1)\n",
    "            x2, y2 = function(x2, y2)\n",
    "            x3, y3 = function(x3, y3)\n",
    "            ctx.curve_to(x1, y1, x2, y2, x3, y3)\n",
    "\n",
    "        elif type == cairo.PATH_CLOSE_PATH:\n",
    "            ctx.close_path()\n",
    "\n",
    "\n",
    "def spiral(x, y):\n",
    "    theta0 = -math.pi * 3 / 4\n",
    "    theta = x / all_width * math.pi * 2 + theta0\n",
    "    radius = y + 200 - x / 7\n",
    "    xnew = radius * math.cos(theta)\n",
    "    ynew = radius * math.sin(-theta)\n",
    "    return xnew + all_width / 2, ynew + all_height / 2\n",
    "\n",
    "\n",
    "def curl(x, y):\n",
    "    xn = x - text_width / 2\n",
    "    xnew = xn\n",
    "    ynew = y + xn ** 3 / ((text_width / 2) ** 3) * 70\n",
    "    return xnew + all_width / 2, ynew + all_height * 2 / 5\n",
    "\n",
    "\n",
    "@disp\n",
    "def draw(ctx, width, height):\n",
    "    global text_width, all_width, all_height\n",
    "\n",
    "    all_width, all_height = width, height\n",
    "\n",
    "    solidpattern = ctx.get_source()\n",
    "\n",
    "    # background\n",
    "    pat = cairo.LinearGradient(0.0, 0.0, 0, height)\n",
    "    pat.add_color_stop_rgba(1, 0, 0, 0, 1)\n",
    "    pat.add_color_stop_rgba(0, 1, 1, 1, 1)\n",
    "\n",
    "    ctx.rectangle(0, 0, width, height)\n",
    "    ctx.set_source(pat)\n",
    "    ctx.fill()\n",
    "\n",
    "    # foreground\n",
    "    ctx.set_source(solidpattern)\n",
    "    ctx.set_source_rgb(1, 1, 1)\n",
    "\n",
    "    ctx.select_font_face(\"Sans\")\n",
    "    ctx.set_font_size(80)\n",
    "\n",
    "    # spiral text\n",
    "    ctx.new_path()\n",
    "    ctx.move_to(0, 0)\n",
    "    ctx.text_path(\"pycairo - \" + \"spam \" * 5)\n",
    "    warpPath(ctx, spiral)\n",
    "    ctx.fill()\n",
    "\n",
    "    # curly text\n",
    "    ctx.new_path()\n",
    "    ctx.move_to(0, 0)\n",
    "    ctx.set_source_rgb(0.3, 0.3, 0.3)\n",
    "    text = \"I am curly :)\"\n",
    "    ctx.text_path(text)\n",
    "    text_width = ctx.text_extents(text)[2]\n",
    "    warpPath(ctx, curl)\n",
    "    ctx.fill()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 23,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "[encoded data, 6368 characters]\n",
      "text/plain": [
       "<IPython.core.display.Image object>"
      ]
     },
     "metadata": {
      "image/png": {
       "width": 200
      }
     },
     "output_type": "display_data"
    }
   ],
   "source": [
    "from contextlib import contextmanager\n",
    "\n",
    "@disp\n",
    "def draw(ctx, width, height):\n",
    "    cr = ctx\n",
    "    @contextmanager\n",
    "    def saved(cr):\n",
    "        cr.save()\n",
    "        try:\n",
    "            yield cr\n",
    "        finally:\n",
    "            cr.restore()\n",
    "\n",
    "    def Tree(angle):\n",
    "        cr.move_to(0, 0)\n",
    "        cr.translate(0, -65)\n",
    "        cr.line_to(0, 0)\n",
    "        cr.stroke()\n",
    "        cr.scale(0.72, 0.72)\n",
    "        if angle > 0.12:\n",
    "            for a in [-angle, angle]:\n",
    "                with saved(cr):\n",
    "                    cr.rotate(a)\n",
    "                    Tree(angle * 0.75)\n",
    "\n",
    "\n",
    "    cr.translate(140, 203)\n",
    "    cr.set_line_width(5)\n",
    "    Tree(0.32)"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "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.8.6"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
