Encode Diagrams

When using GET requests, your diagram must be encoded in the URL using a deflate + base64 algorithm. On this page you will learn how to encode a diagram using:

To decode a diagram (e.g. from Kroki log message) we recommend using Kroki CLI or one of the decoders listed on the Third Party Tools page.

Node.js

To compress our diagram with deflate algorithm, we are going to use pako — a high speed zlib port to JavaScript. Once pako is installed, you can use the deflate method:

const pako = require('pako')

const diagramSource = `digraph G {
  Hello->World
}`

const data = Buffer.from(diagramSource, 'utf8') 
const compressed = pako.deflate(data, { level: 9 }) 
const result = Buffer.from(compressed)
  .toString('base64') 
  .replace(/\+/g, '-').replace(/\//g, '_') 

console.log(result)
1 Create a Buffer from the diagram source using the default UTF-8 encoding
2 Compress data with deflate algorithm using a compression level of 9 (best compression).
3 Create a Buffer from the compressed data and encode to Base64
4 Replace + and / characters to make it "URL safe"

JavaScript

We recommend encoding your diagram as UTF-8. To do so, we can use TextEncoder:

new TextEncoder('utf-8').encode(diagramSource)

Unfortunately TextEncoder is not yet available on all browsers. To workaround this issue, we can define a function to encode our diagram:

function textEncode(str) {
  if (window.TextEncoder) {
    return new TextEncoder('utf-8').encode(str);
  }
  var utf8 = unescape(encodeURIComponent(str));
  var result = new Uint8Array(utf8.length);
  for (var i = 0; i < utf8.length; i++) {
    result[i] = utf8.charCodeAt(i);
  }
  return result;
}

The above code will use TextEncoder if it’s available and otherwise it will use a fallback implementation.

Now that our diagram is encoded as UTF-8 in a Uint8Array, we can use pako to compress it. As a reminder, pako is a high speed zlib port to JavaScript:

<script src="https://unpkg.com/pako@1.0.10/dist/pako_deflate.min.js"></script>

To compress our diagram diagram we are going to use the deflate method provided by pako:

var diagramSource = 'digraph G { Hello->World }'

var data = textEncode(diagramSource) 
var compressed = pako.deflate(data, { level: 9, to: 'string' }) 
var result = btoa(compressed) 
  .replace(/\+/g, '-').replace(/\//g, '_') 

console.log(result)
1 Encode the diagram as UTF8 in a Uint8Array (using the textEncode function declared above)
2 Compress data with deflate algorithm using a compression level of 9 (best compression). pako is available as a global variable.
3 Encode to Base64 using btoa global function
4 Replace + and / characters to make it "URL safe"

Python

import sys;
import base64;
import zlib;

print(base64.urlsafe_b64encode(zlib.compress(sys.stdin.read(), 9)))

Java

package main;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.util.Base64;
import java.util.zip.Deflater;

public class Encode {

  public static byte[] encode(String decoded) throws IOException {
    return Base64.getUrlEncoder().encode(compress(decoded.getBytes()));
  }

  private static byte[] compress(byte[] source) throws IOException {
    Deflater deflater = new Deflater(Deflater.BEST_COMPRESSION);
    deflater.setInput(source);
    deflater.finish();

    byte[] buffer = new byte[2048];
    int compressedLength = deflater.deflate(buffer);
    byte[] result = new byte[compressedLength];
    System.arraycopy(buffer, 0, result, 0, compressedLength);
    return result;
  }
}

Kotlin

package main

import java.util.Base64
import java.util.zip.Deflater

object Encode {

  fun encode(decoded: String): String =
    String(Base64.getUrlEncoder().encode(compress(decoded.toByteArray())), Charsets.UTF_8)

  private fun compress(source: ByteArray): ByteArray {
    val deflater = Deflater()
    deflater.setInput(source)
    deflater.finish()
    val bytesCompressed = ByteArray(Short.MAX_VALUE.toInt())
    val numberOfBytesAfterCompression = deflater.deflate(bytesCompressed)
    val returnValues = ByteArray(numberOfBytesAfterCompression)
    System.arraycopy(bytesCompressed, 0, returnValues, 0, numberOfBytesAfterCompression)
    return returnValues
  }
}

Go

package main

import (
	"bytes"
	"compress/zlib"
	"encoding/base64"

	"github.com/pkg/errors"
)

// Encode takes a string and returns an encoded string in deflate + base64 format
func Encode(input string) (string, error) {
	var buffer bytes.Buffer
	writer, err := zlib.NewWriterLevel(&buffer, 9)
	if err != nil {
		return "", errors.Wrap(err, "fail to create the writer")
	}
	_, err = writer.Write([]byte(input))
	writer.Close()
	if err != nil {
		return "", errors.Wrap(err, "fail to create the payload")
	}
	result := base64.URLEncoding.EncodeToString(buffer.Bytes())
	return result, nil
}

PHP

<?php

function base64url_encode($data) {
  return rtrim(strtr(base64_encode($data), '+/', '-_'), '=');
}

function encode($data) {
  return base64url_encode(gzcompress($data));
}

Tcl

# assuming the diagram code is stored in the variable named `diagramSource`:
puts [string map {+ - / _} [binary encode base64 [zlib compress $diagramSource]]]

Also, see the Tcl package dia2kroki which has procedures to both decode and encode the diagram source code and a GUI to create diagrams with a live preview.

Elixir

:zlib.compress(graph)
|> Base.url_encode64()

C#

using System;
using System.IO;
using System.IO.Compression;
using System.Text;

class Program
{
    static byte[] Deflate(byte[] data, CompressionLevel? level = null)
    {
        using (var memStream = new MemoryStream())
        {
#if NET6_0_OR_GREATER
            using(ZLibStream zlibStream = level.HasValue ? new(memStream, level.Value, true) : new(memStream, CompressionMode.Compress, true))
            {
                zlibStream.Write(data);
            }
#else

            // Reference: https://yal.cc/cs-deflatestream-zlib/#code

            // write header:
            memStream.WriteByte(0x78);
            memStream.WriteByte(level switch
            {
                CompressionLevel.NoCompression or CompressionLevel.Fastest => 0x01,
                CompressionLevel.Optimal => 0x0A,
                _ => 0x9C,
            });

            // write compressed data (with Deflate headers):
            using (DeflateStream dflStream = level.HasValue ? new(memStream, level.Value, true) : new(memStream, CompressionMode.Compress, true))
            {
                dflStream.Write(data, 0, data.Length);
            }

            // compute Adler-32:
            uint a1 = 1, a2 = 0;
            foreach (byte b in data)
            {
                a1 = (a1 + b) % 65521;
                a2 = (a2 + a1) % 65521;
            }

            memStream.WriteByte((byte)(a2 >> 8));
            memStream.WriteByte((byte)a2);
            memStream.WriteByte((byte)(a1 >> 8));
            memStream.WriteByte((byte)a1);

#endif

            return memStream.ToArray();
        }

        
    }

    public static void Main(string[] args)
    {
        var compressedBytes = Deflate(Encoding.UTF8.GetBytes("digraph G {Hello->World}"));
#if NET9_0_OR_GREATER
        // You can use this in previous version of .NET  with Microsoft.Bcl.Memory package
        var encodedOutput = System.Buffers.Text.Base64Url.EncodeToString(compressedBytes);
#else
        var encodedOutput = Convert.ToBase64String(compressedBytes).Replace('+', '-').Replace('/', '_');
#endif
        Console.WriteLine($"https://kroki.io/graphviz/svg/{encodedOutput}");
    }
}
Please note that we cannot use we cannot use System.IO.Compression.DeflateStream because it does not include ZLIB header/trailer. To learn more, please read: yal.cc/cs-deflatestream-zlib/#code