0
Rendering Microsoft Tags

Rendering Microsoft Tags in .tag Format

Rendering a Microsoft Tag in the .tag file format provides a hexadecimal code that you can use to programmatically generate the Tag in other applications. This documentation explains how to interpret the hexadecimal encoding of a Tag and how to generate a scannable graphic.


Download a .pdf version of this information.

General Layout

Microsoft Tags are available in a four-color version (using pure versions of cyan, magenta, yellow, and black) and in a larger black-and-white version. Each Tag includes:

general layout

The symbols within a standard Tag are triangles. However, for custom Tags, the symbols can be dots. The symbol rows are separated from the frame and from one another by row spacers. The black frame is enclosed in a white border; the width of the white border is equal to the height of the bottom black bar.


The number of symbol rows depends on the Tag type. Standard color Tags have five symbol rows, whereas standard black-and-white Tags have seven. Regardless of type, Tags always have twice as many symbols per row as they have rows. For example, standard, five-row color Tags will always have 10 symbols per row. Standard black-and-white Tags will always have 14 symbols per row.

Getting Started with the Tag Web Services API

Microsoft Tags are represented in hexadecimal format that can be stored in the .tag file format. They can also be retrieved from the Microsoft Tag API. Each .tag file can contain one or more hexadecimal encodings of a given Tag to allow the Tag graphic to be created in different formats. Different formats will be separated by a semicolon and a space.


Note: The encoding for a color Tag inside a .tag file cannot be converted to a black-and-white Tag. To interpret the hexadecimal code for a Tag, use the following guidelines:


1. The first character in the series indicates the Tag type. Currently, the only possible values are zero (black-and-white) or one (color). The interpretation of the rest of the characters in the encoding is determined by the Tag type.


2. For both color and black-and-white Tag types, the second character in the series indicates the number of rows that make up the Tag. While standard black-and-white Tags are made up of seven rows each and standard color Tags are made up of five rows each, Tags created in the future can consist of as few as four rows and as many as 15 rows.


3. For both of these Tag types, the third and subsequent characters specify the color of each symbol within the Tag. The Tag symbols are encoded left to right, starting with the first row. For color Tags, each character contains two symbols. For black-and-white Tags, each character represents four symbols. If the number of symbols in a Tag does not divide evenly by two (for a color Tag) or four (for a black-and-white Tag), the last character will be padded with zero-valued symbols as necessary.


Each symbol within a black-and-white Tag corresponds to a one-bit value. Each symbol within a color Tag corresponds to a two-bit value.


The color values used for the symbols in a Tag are shown in the following table.

Color Tags (2-bit values) Black and White Tags (1-bit values)
00Yellow 0Black
01Magenta 1White
10Black
11Cyan

For example, let’s look at the hexadecimal values for both a color Tag and a black-and-white Tag that, when scanned, will open the Microsoft Tag website at http://tag.microsoft.com.


The color Tag for this URL looks like this:

Color Tag

The hexadecimal code for this Tag, when rendered in the .tag format is:


15CCFC25B0BCDC61F83E5FC711B


The initial character, 1, indicates that this is a color tag. The second character, 5, indicates the number of rows in the Tag – this Tag has five rows. The third value, C, indicates the first two symbols in the row. Each subsequent hexadecimal character represents two symbols in a symbol row. Translated from the hexadecimal, C becomes “1100,” which designates a cyan symbol followed by a yellow symbol, as you can see in the Tag itself. The rest of the hexadecimal characters are interpreted in the same way.


In contrast, let’s look at the image and coding for the black-and-white Tag that opens the same website.


The black-and-white Tag for this URL looks like this:

Black Tag

The hexadecimal code for this Tag is:


07A169EEF34AF2E138806187174


In the above example, each hexadecimal character represents four symbols in a symbol row. The initial character, 0, indicates that this is a black-and-white Tag. The second character, 7, indicates the number of rows in the Tag – this Tag has seven rows. When converted from hexadecimal, the third character, A, gives us 1010. Because this is a black-and-white Tag, 1010 here designates four symbols: white black white black.

Calculating Sizes

To design a Tag, you must calculate its basic unit size. (In these guidelines, “unit” refers to any unit of measure upon which the Tag is based.)


Use the following rules to calculate the size of the Tag:

  • Each row of symbols within a Tag must be seven units tall.
  • A row spacer, two units high, must be included:
    • Above the first row
    • Between each row
    • Below the last row
      The row spacers extend two units into the left and right edges of the black frame
  • The black frame that surrounds the Tag symbols must have the following dimensions:
    • three units tall on top
    • five units wide on the left and right sides
    • seven units tall on the bottom
  • The white border that surrounds all four sides of he Tag must be seven units thick.
Tag Sizes

The following table shows how to calculate the dimensions of sample color and black-and-white Tags.

Tag Dimension Color Tags Black/White Tags
No of Rows 5 7
Bar Code Height (in Units)
  • 7 for the top white border
  • 3 for the top frame
  • 7 for the bottom black frame
  • 7 for the bottom white border
  • 2 between rows and between rows and frames 7+3+7+7+7*Rows+2*(Rows+1)=26+9*Rows
26+9*5 = 71 26+9*7 = 89
Symbols Per Row Note: This number is always equal to 2*Rows. 10 14
Row Width (in Units):
  • 7 for the left white border
  • 5 for the left black frame
  • 5 for the right black frame
  • 7 for the bottom white border
  • 7 for the right white border
71-24 = 47 89-24 = 65
Symbols Widths Per Row The symbols are laid out in a triangle pattern. So, the actual triangle widths that fit into a particular row are equal to one-half the number of symbols plus half of the symbol.
Base Width = Symbols Per Row / 2 + ½
10/2 + ½ = 14/2 + ½ =
Symbol Width (in Units) The width of the triangle symbol is calculated by dividing the row width by the width of symbols. 47/5.5 = 8.545 65/7.5 = 8.533

Drawing the Symbols

All shapes are drawn based on the actual size of the bar code and the calculated unit size. For example, if you are publishing a Tag in a magazine, you may choose to create a Tag that is one-inch square. A five-line, one-inch bar code has 71 units, so each unit is 0.014085 inches. The bottom black frame is seven units tall, so it works out to 7/71*1 inches tall, or 0.098592 inches. If, instead of publishing a one-inch Tag in a magazine, you plan to create a Tag that will be displayed on a billboard, you will have to calculate much larger units to ensure that your Tag can be scanned from a distance.


The following table shows the relative size of each type of Tag.

Size (in relation to overall size) 5-row color Tag 7-row Black/White Tag
White Border 7/71 7/89
Black Frame (Top) 3/71 3/89
Black Frame (Sides) 5/71 5/89
Black Frame (Bottom) 7/71 7/89
Frame Height and Width 57/71 75/89
Row Spacers Height 2/71 2/89
Row Spacer Width 51/71 69/89
Row Overlay over Frame Sides 2/71 2/89
Row Width 2/71 2/89
Triangle Height 7/71 7/89
Triangle Width at Base 47/(71*5.5) 65/(89*7.5)

Example: Standard Tag

standard

Between the black frame and the first triangle in a row of symbols is a half-triangle that is black. The first full triangle in the row is drawn next to the black half-triangle, base-side up. The last triangle of a row is drawn base-side down, followed by a black half-triangle between it and the black frame on the right of the Tag.

Example: Custom Tag

custom

When drawing a very basic custom Tag, the symbols are drawn as dots instead of triangles and a barcode background – in this case, the blue field – shows through the space between the frames. The first and last row spacers are white, as are the remaining row spacers that overlap the frame sides. The background should show through the row-spacers that are between the rows and between the frames. In addition, the background shows through the parts of each triangular symbol that is not taken up by the dots and the additional half-triangle spaces at the beginning and the end of each row. In other words, the background shows through every position inside the frame except where the dots and the top and bottom row spacers appear.


tag diagram

Dots are drawn with a diameter that is one-third of the width of the triangles. The dots must be horizontally aligned at the center of each triangle and vertically aligned one-third of the way toward the center of the triangle as measured from the triangle’s base.

Rendering Microsoft Tags Sample Code

Rendering a Microsoft Tag in the .tag file format provides a hexadecimal code that you can use to programmatically generate the Tag. The above information explains how to interpret the hexadecimal encoding of a Tag, and how to generate a scannable graphic. The following sample code demonstrates generating a PNG image of a Tag in C#.


using System;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Drawing.Imaging;
using System.Globalization;
namespace RenderTagCode
{
  class Program
  {
    private static Image RenderTag(string tagCode, int sizeInPixels)
    {
      // check the arguments
      if (string.IsNullOrEmpty(tagCode) || !tagCode.StartsWith("15"))
      {
        throw new ArgumentException("Only tag codes for 5-row color 
          tags are supported.");
      }

      // constants: tag layout
      const int rows = 5;
      const int symbolsPerRow = 10;

      // constants: dimensions of inner tag components, in "units"
      const int whiteBorderThickness = 7;
      const int blackFrameTopThickness = 3;
      const int blackFrameBottomThickness = 7;
      const int blackFrameHorizThickness = 5;
      const int rowHeight = 7;
      const int rowSpacerHeight = 2;
      const int rowSpacerHang = 2;

      const int rowsAreaHeight = rows * rowHeight 
            + (rows + 1) * rowSpacerHeight;
      const int blackFrameSize = blackFrameTopThickness 
            + rowsAreaHeight + blackFrameBottomThickness;
      const int rowsAreaWidth = blackFrameSize - 2 
            * blackFrameHorizThickness;
      const int whiteBorderSize = 2 * whiteBorderThickness 
            + blackFrameSize;

      const float halfSymbolWidth = ((float)rowsAreaWidth) 
            / (symbolsPerRow + 1);

      // areas surrounding the inner tag components
      Rectangle whiteBorderRect = new Rectangle(0, 0, 
            whiteBorderSize, whiteBorderSize);
      Rectangle blackFrameRect = new Rectangle(whiteBorderThickness, 
            whiteBorderThickness, blackFrameSize, blackFrameSize);
      Rectangle rowsAreaRect = new Rectangle(blackFrameRect.Left 
            + blackFrameHorizThickness, blackFrameRect.Top 
            + blackFrameTopThickness, rowsAreaWidth, rowsAreaHeight);

      // brushes for the colors used
      Brush whiteBrush = new SolidBrush(Color.White);
      Brush blackBrush = new SolidBrush(Color.Black);
      Brush[] brushes = new Brush[]
      {
        new SolidBrush(Color.Yellow),   // 00
        new SolidBrush(Color.Magenta),  // 01
        blackBrush,                     // 10
        new SolidBrush(Color.Cyan),     // 11
      };

      // render the tag to a bitmap
      Bitmap bitmap = new Bitmap(sizeInPixels, sizeInPixels, 
      PixelFormat.Format32bppArgb);
      using (Graphics g = Graphics.FromImage(bitmap))
      {
        // scale all graphics dimensions to use tag units
        Matrix matrix = new Matrix();
        float scaleFactor = ((float)sizeInPixels) / whiteBorderSize;
        matrix.Scale(scaleFactor, scaleFactor);
        g.Transform = matrix;

        // fill the white border and black frame
        g.FillRectangle(whiteBrush, whiteBorderRect);
        g.FillRectangle(blackBrush, blackFrameRect);

        // fill the row spacers in white
        for (int row = 0; row <= rows; ++row)
        {
          g.FillRectangle(
          whiteBrush,
          rowsAreaRect.Left - rowSpacerHang,
          rowsAreaRect.Top + row * (rowSpacerHeight + rowHeight),
          rowsAreaRect.Width + 2 * rowSpacerHang,
          rowSpacerHeight);
        }

        // fill the triangular symbols; the first two characters in
        // the tag code indicate the tag color scheme and row count,
        // and are skipped.
        for (int i = 2; i < tagCode.Length; ++i)
        {
          // read the next hex digit
          int hexDigit = int.Parse(tagCode.Substring(i, 1), 
            NumberStyles.HexNumber);
          int firstSymbolCode = (hexDigit >> 2) & 0x03;
          int secondSymbolCode = hexDigit & 0x03;

          // find out the row and column for the two symbols needed
          // to represent the hex digit
          int row = (i - 2) / (symbolsPerRow / 2);
          int col = ((i - 2) % (symbolsPerRow / 2)) * 2;

          // compute the position of the symbols, in units
          float left = rowsAreaRect.Left + col * halfSymbolWidth;
          float top = rowsAreaRect.Top + rowSpacerHeight 
            + row * (rowSpacerHeight + rowHeight);
          float bottom = top + rowHeight;

          // fill the triangular symbols
          g.FillPolygon(
            brushes[firstSymbolCode],
            new PointF[]
            {
              new PointF(left + 0 * halfSymbolWidth, top),
              new PointF(left + 1 * halfSymbolWidth, bottom),
              new PointF(left + 2 * halfSymbolWidth, top)
            });

          g.FillPolygon(
            brushes[secondSymbolCode],
            new PointF[]
            {
              new PointF(left + 1 * halfSymbolWidth, bottom),
              new PointF(left + 2 * halfSymbolWidth, top),
              new PointF(left + 3 * halfSymbolWidth, bottom)
            });
        }
      }
      return bitmap;
    }

    static void Main(string[] args)
    {
      RenderTag("152B4824C3F5DC61A02337C711B", 600).Save("image.png");
    }
  }
}
arrow

Best Practices for Using Tag

Design Tags that scan easily and offer an engaging mobile experience

arrow

Add Location Awareness to Your Tags

Target your message based on the customer’s geographical location