Skip to content

Instantly share code, notes, and snippets.

@tcyrus
Created February 9, 2019 22:08
Show Gist options
  • Select an option

  • Save tcyrus/2263d44ee98ff40935a0148a2dca4ae3 to your computer and use it in GitHub Desktop.

Select an option

Save tcyrus/2263d44ee98ff40935a0148a2dca4ae3 to your computer and use it in GitHub Desktop.
Display the source blob
Display the rendered blob
Raw
{
"cells": [
{
"metadata": {},
"cell_type": "markdown",
"source": "# Jdenticon Generation from F# Notebook\n\nI try to document all procedural generation for things like avatars. My latest avatar for \"tcyr.us\" is created using Jdenticon. Jdenticon has 3 official software impelementations: JavaScript, .NET, and PHP. The only one of those which had a supported Jupyter Kernel was .NET (via F#).\n\nThe catch is the implementation needs some hacks to get it working with F#."
},
{
"metadata": {},
"cell_type": "markdown",
"source": "First things first, get the `Jdenticon-net` package via NuGet via Paket."
},
{
"metadata": {
"trusted": true
},
"cell_type": "code",
"source": "#load \"Paket.fsx\"\nPaket.Package [ \"Jdenticon-net\" ]\n#load \"Paket.Generated.Refs.fsx\"",
"execution_count": 8,
"outputs": []
},
{
"metadata": {},
"cell_type": "markdown",
"source": "So far so good..."
},
{
"metadata": {
"trusted": true
},
"cell_type": "code",
"source": "open Jdenticon\nopen Jdenticon.Rendering",
"execution_count": 9,
"outputs": []
},
{
"metadata": {},
"cell_type": "markdown",
"source": "Custom identicon style can be found [here](https://jdenticon.com/icon-designer.html?config=2a4766ff10cd322d33552c41).\n\nThis was my attempt at porting the example code from C# to F#. This is somewhat hacky since some of the code doesn't actually translate well into an immutable model. Feel free to contact me if there is a better way to do any of this."
},
{
"metadata": {},
"cell_type": "markdown",
"source": "First, `HueCollection` is in the `Jdenticon.Rendering` namespace. The sample code relies on exploiting collection initializers, something which works in C# but not F#. This uses a `let` binding expression as an ugly but functional solution (no pun intended)."
},
{
"metadata": {
"trusted": true
},
"cell_type": "code",
"source": "let hues =\n let tmp = new HueCollection()\n tmp.Add(205.0f, HueUnit.Degrees)\n tmp",
"execution_count": 10,
"outputs": []
},
{
"metadata": {},
"cell_type": "markdown",
"source": "This code uses F# Property Initializer, the closest thing I could find to the C# Object Initializer."
},
{
"metadata": {
"trusted": true
},
"cell_type": "code",
"source": "let style = new IdenticonStyle(Hues = hues,\n BackColor = Color.FromRgba(42, 71, 102, 255),\n ColorLightness = Range.Create(0.51f, 0.85f),\n GrayscaleLightness = Range.Create(0.44f, 0.65f),\n ColorSaturation = 0.50f,\n GrayscaleSaturation = 0.45f)",
"execution_count": 11,
"outputs": []
},
{
"metadata": {},
"cell_type": "markdown",
"source": "Since I couldn't use the Property Initializer here, I had to use another `let` binding expression."
},
{
"metadata": {
"trusted": true
},
"cell_type": "code",
"source": "let avatar = \n let tmp = Identicon.FromValue(\"tcyr.us\", size=512)\n tmp.Style <- style\n tmp",
"execution_count": 12,
"outputs": []
},
{
"metadata": {},
"cell_type": "markdown",
"source": "Since `IfSharp` doesn't support SVG rendering directly, I improvised. I used `AddDisplayPrinter` to tell the `Display` function how to handle `Identicon` objects. Since browsers will render SVG inline, I can use the `\"text/html\"` option for `ContentType` and hope for the best."
},
{
"metadata": {
"trusted": true
},
"cell_type": "code",
"source": "open IfSharp.Kernel.App\n\nAddDisplayPrinter (fun (id: Identicon) -> { ContentType = \"text/html\"; Data = id.ToSvg() })",
"execution_count": 13,
"outputs": []
},
{
"metadata": {
"trusted": true
},
"cell_type": "markdown",
"source": "Now, the moment of truth..."
},
{
"metadata": {
"trusted": true
},
"cell_type": "code",
"source": "avatar",
"execution_count": 14,
"outputs": [
{
"output_type": "execute_result",
"execution_count": 14,
"data": {
"text/html": "<svg xmlns=\"http://www.w3.org/2000/svg\" width=\"512\" height=\"512\" viewBox=\"0 0 512 512\" preserveAspectRatio=\"xMidYMid meet\"><rect fill=\"#2a4766\" fill-opacity=\"1\" x=\"0\" y=\"0\" width=\"512\" height=\"512\"/><path fill=\"#c1d9ea\" d=\"M256 149L149 149L149 95.5ZM256 149L256 42L309.5 42ZM256 363L363 363L363 416.5ZM256 363L256 470L202.5 470ZM149 256L42 256L42 202.5ZM363 256L363 149L416.5 149ZM363 256L470 256L470 309.5ZM149 256L149 363L95.5 363Z\"/><path fill=\"#386e95\" d=\"M59.83369 95.49999a35.66631,35.66631 0 1,1 71.33263,0a35.66631,35.66631 0 1,1 -71.33263,0M380.8337 95.5a35.66631,35.66631 0 1,1 71.33263,0a35.66631,35.66631 0 1,1 -71.33263,0M380.8337 416.5a35.66631,35.66631 0 1,1 71.33263,0a35.66631,35.66631 0 1,1 -71.33263,0M59.83368 416.5a35.66631,35.66631 0 1,1 71.33263,0a35.66631,35.66631 0 1,1 -71.33263,0\"/><path fill=\"#7aaed2\" d=\"M175 175L246 175L246 246L175 246ZM337 175L337 246L266 246L266 175ZM337 337L266 337L266 266L337 266ZM175 337L175 266L246 266L246 337Z\"/></svg>"
},
"metadata": {}
}
]
}
],
"metadata": {
"kernelspec": {
"name": "ifsharp",
"display_name": "F#",
"language": "fsharp"
},
"language_info": {
"mimetype": "text/x-fsharp",
"nbconvert_exporter": "",
"name": "fsharp",
"pygments_lexer": "",
"version": "4.3.1.0",
"file_extension": ".fs",
"codemirror_mode": ""
},
"language": "fsharp"
},
"nbformat": 4,
"nbformat_minor": 2
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment