# Images and Barcodes

> Merge images, barcodes and charts in Windows Forms: named placeholders, Select Frame Data Column, TXBarcodeControl, Base64 and SVG data, chart data relations.

- **Product:** TX Text Control .NET for Windows Forms
- **Section:** Documentation
- **Kind:** Topic
- **Path:** TX Text Control .NET for Windows Forms > Mail Merge and Reporting > Images and Barcodes
- **5147 words**
- **Web URL:** https://docs.textcontrol.com/tx-text-control-dotnet-winforms/mail-merge/images-barcodes/
- **LLMs URL:** https://docs.textcontrol.com/tx-text-control-dotnet-winforms/mail-merge/images-barcodes/llms.txt
- **LLMs-Full URL:** https://docs.textcontrol.com/tx-text-control-dotnet-winforms/mail-merge/images-barcodes/llms-full.txt

---

A logo, a product photo or a signature can come from the data just like a name or an amount, and so can the value a QR code or barcode encodes. The template holds a placeholder for each: an image or a barcode with a name. During the merge, `MailMerge` fills every placeholder whose name matches a field of the data, and the placeholder keeps its position and size. You create placeholders in the Reporting tab and in code, merge images from Base64 data, files and SVG, merge values into barcodes and check them first, and fill charts from the tables of the data.

Here, the invoice of [Merge Data into Fields](https://docs.textcontrol.com/tx-text-control-dotnet-winforms/getting-started/mail-merge/fields/llms-full.txt) gets a logo and a QR code for the invoice number. Images and barcodes that your code adds to documents without a merge are described in [Images, Text Frames, and Shapes](https://docs.textcontrol.com/tx-text-control-dotnet-winforms/document-processing/images-shapes/llms-full.txt) and [Charts and Barcodes](https://docs.textcontrol.com/tx-text-control-dotnet-winforms/document-processing/charts-barcodes/llms-full.txt).

### How Placeholders Work

A placeholder is an ordinary image or barcode in the template whose name matches a field of the data. `MailMerge` handles it like a merge field:

- **Image data.** The value of the field can be a byte array, a `System.Drawing.Image`, a Base64 string, a hexadecimal string that starts with `X'`, the name of an image file or, since version 32.0 SP3, SVG markup as plain XML text.
- **Size and layout.** A merged image is scaled to the width of the placeholder and keeps its position and text flow, such as an image anchored at the right of a paragraph.
- **Barcodes** keep their type, size and position; only the encoded text changes.
- **Blocks.** Placeholders in a merge block are merged for each record, so a product table can show a photo or a barcode in each row.
- **Names.** Placeholder names follow the rules of merge field names, including dot notation for related data.
- **Missing data.** An image placeholder without data stays in the document unless [RemoveEmptyImages](https://docs.textcontrol.com/tx-text-control-dotnet-winforms/reference/txtextcontrol-documentserver/mailmerge/removeemptyimages-property/llms-full.txt) is `true`; its default is `false`.

Save templates with placeholders in the TX Text Control format, *invoice.tx*, as the samples of Text Control do.

Both kinds of placeholders can fill one document. The following packing slip was merged from JSON data: the QR code at the top and the linear barcode in each row of the item block received their values from the data. The blog article [Enhancing Documents with QR Codes and Barcodes in .NET C#: A Comprehensive Guide](https://www.textcontrol.com/blog/2024/07/11/enhancing-documents-with-qr-codes-and-barcodes-in-net-csharp-a-comprehensive-guide/) shows its template and data:

![A merged packing slip with a QR code in the upper right corner and a linear barcode at the end of each of its eight item rows.](https://docs.textcontrol.com/assets/img/tx-text-control-dotnet-winforms/packing-slip-barcodes.4a025714.webp)

### Create Placeholders With the Ribbon

Users insert an image with the **Image** button or a barcode with the **Barcode** drop-down of the **Insert** tab. The drop-down lists the barcode types:

![TX Words with the Barcode drop-down of the Insert tab open, listing QRCode, Code128, EAN13 and other barcode types, and shipping labels with barcodes in the document.](https://docs.textcontrol.com/assets/img/tx-text-control-dotnet-winforms/insert-tab-barcode-menu.ea6bd4b9.webp)

The name connects the placeholder with the data. With the image or barcode selected, the name can be typed into the object name box of the contextual **Frame Formatting** tab, the [RibbonFrameLayoutTab](https://docs.textcontrol.com/tx-text-control-dotnet-winforms/reference/txtextcontrol-windows-forms-ribbon/ribbonframelayouttab/llms-full.txt). When a data source is loaded into the Reporting tab, the **Insert Merge Field** button of the **Merge Fields** group becomes **Select Frame Data Column** while an image or barcode is selected, and lists the columns to choose the name from:

![The Select Frame Data Column drop-down of the Reporting tab listing the columns of a table and of related tables, with an image placeholder selected in the document.](https://docs.textcontrol.com/assets/img/tx-text-control-dotnet-winforms/frame-data-column-menu.b2142b48.webp)

### Create Placeholders in Code

In code, a placeholder is an image or barcode frame with a [Name](https://docs.textcontrol.com/tx-text-control-dotnet-winforms/reference/txtextcontrol/framebase/name-property/llms-full.txt). The following handlers insert a logo placeholder and a QR code at the input position of `textControl1`. Add `using System.Drawing;`, `using TXTextControl.Barcode;` and `using TXTextControl.DataVisualization;` to *Form1.cs*:

```csharp
private void insertLogoPlaceholderButton_Click(object sender, EventArgs e)
{
    // TXTextControl.Image, not System.Drawing.Image; 4 is the filter index of PNG
    TXTextControl.Image placeholder = new TXTextControl.Image("placeholder.png", 4);

    // Insert the image inline at the input position
    textControl1.Images.Add(placeholder, -1);

    // The name connects the placeholder with the data
    placeholder.Name = "Logo";
}

private void insertQrCodeButton_Click(object sender, EventArgs e)
{
    TXBarcodeControl qrCode = new TXBarcodeControl
    {
        BarcodeType = BarcodeType.QRCode,
        // The size of the code is calculated for 12 characters
        UpperTextLength = 12,
        Text = "INV-0000-000"
    };

    BarcodeFrame barcodeFrame = new BarcodeFrame(qrCode)
    {
        // The name connects the barcode with the data
        Name = "InvoiceNumber",
        Size = new Size(1440, 1440) // 1 inch in twips
    };

    textControl1.Barcodes.Add(barcodeFrame, -1);
}
```

The code works as follows:

- The [Image constructor](https://docs.textcontrol.com/tx-text-control-dotnet-winforms/reference/txtextcontrol/image/constructor/llms-full.txt) loads the placeholder picture; with `using System.Drawing;` in the file, the class name must be written as `TXTextControl.Image`. [ImageCollection.Add](https://docs.textcontrol.com/tx-text-control-dotnet-winforms/reference/txtextcontrol/imagecollection/add-method/llms-full.txt) with `-1` inserts it at the input position. The size you give the placeholder is the width of every merged image.
- [TXBarcodeControl](https://docs.textcontrol.com/tx-text-control-dotnet-winforms/reference/txtextcontrol-barcode/txbarcodecontrol/llms-full.txt) defines the barcode: its [BarcodeType](https://docs.textcontrol.com/tx-text-control-dotnet-winforms/reference/txtextcontrol-barcode/txbarcodecontrol/barcodetype-property/llms-full.txt) and the [Text](https://docs.textcontrol.com/tx-text-control-dotnet-winforms/reference/txtextcontrol-barcode/txbarcodecontrol/text-property/llms-full.txt) shown until the merge.
- The [BarcodeFrame constructor](https://docs.textcontrol.com/tx-text-control-dotnet-winforms/reference/txtextcontrol-datavisualization/barcodeframe/constructor/llms-full.txt) places the barcode in the document. Its `Name` is matched with the data, and its `Size` in twips is the space the barcode takes.
- [TextControl.Barcodes](https://docs.textcontrol.com/tx-text-control-dotnet-winforms/reference/txtextcontrol/textcontrol/barcodes-property/llms-full.txt) returns the [BarcodeCollection](https://docs.textcontrol.com/tx-text-control-dotnet-winforms/reference/txtextcontrol-datavisualization/barcodecollection/llms-full.txt), whose `Add` method inserts the barcode inline; other overloads anchor it to a paragraph or place it at a fixed position.

[UpperTextLength](https://docs.textcontrol.com/tx-text-control-dotnet-winforms/reference/txtextcontrol-barcode/txbarcodecontrol/uppertextlength-property/llms-full.txt) matters for merged barcodes. A barcode must not push the text around it, so its frame keeps its size and the code inside adapts: a text of the maximum length fills the frame, and a shorter text makes the code smaller. Set it to the longest value your data contains, before `Text`. The blog article [Understanding the UpperTextLength of Barcodes in TX Text Control X9](https://www.textcontrol.com/blog/2013/05/09/understanding-the-uppertextlength-of-barcodes-in-tx-text-control-x9/) shows the effect.

### Add the Image Data

JSON carries images as Base64 strings, so the data stays in one file. Add a `Logo` property with the Base64 data of a PNG image to the invoice in *invoice.json*:

```json
[
  {
    "Company": "Contoso Ltd.",
    "Name": "Jane Miller",
    "InvoiceNumber": "INV-1001",
    "Logo": "iVBORw0KGgoAAAANSUhEUgAA...",
    "Items": [
      { "Description": "Consulting", "Quantity": 2, "Price": 150.00 },
      { "Description": "Training", "Quantity": 1, "Price": 480.00 }
    ]
  }
]
```

The value is shortened here; use the complete Base64 string of your image. `InvoiceNumber` already holds the value for the QR code. When the data contains a file name such as `"Logo": "logo.png"` instead, `MailMerge` looks for the file in the folder of [SearchPath](https://docs.textcontrol.com/tx-text-control-dotnet-winforms/reference/txtextcontrol-documentserver/mailmerge/searchpath-property/llms-full.txt), or in the root directory when it is empty. For SVG, the value is the markup itself, not Base64 encoded; the blog article [Service Pack 3: MailMerge Supports SVG Images](https://www.textcontrol.com/blog/2024/04/29/service-pack-3-mailmerge-supports-svg-images/) shows an example.

### Merge Images and Barcodes

The following handler merges *invoice.tx* with the data, removes image placeholders without data and shows the result in the editor. It needs `using System.IO;` and `using TXTextControl.DocumentServer;`:

```csharp
private void mergeImagesButton_Click(object sender, EventArgs e)
{
    byte[] result;

    using (ServerTextControl tx = new ServerTextControl())
    {
        tx.Create();
        tx.Load("invoice.tx", StreamType.InternalUnicodeFormat);

        using (MailMerge mailMerge = new MailMerge
        {
            TextComponent = tx,
            // Remove placeholders the data has no image for
            RemoveEmptyImages = true,
            // Image file names in the data are searched here
            SearchPath = Path.Combine(Application.StartupPath, "Images")
        })
        {
            mailMerge.ImageMerged += (s, args) =>
            {
                if (args.Merged && args.Name == "Logo")
                {
                    args.DescriptiveText = "Company logo";
                }
            };

            mailMerge.BarcodeMerged += (s, args) =>
                System.Diagnostics.Debug.WriteLine("Barcode merged: " + args.BarcodeFrame.Name);

            mailMerge.MergeJsonData(File.ReadAllText("invoice.json"));
        }

        tx.Save(out result, BinaryStreamType.InternalUnicodeFormat);
    }

    textControl1.Load(result, BinaryStreamType.InternalUnicodeFormat);
}
```

The code works as follows:

- [ImageMerged](https://docs.textcontrol.com/tx-text-control-dotnet-winforms/reference/txtextcontrol-documentserver/mailmerge/imagemerged-event/llms-full.txt) occurs for each image placeholder. Its arguments tell the [Name](https://docs.textcontrol.com/tx-text-control-dotnet-winforms/reference/txtextcontrol-documentserver/mailmerge-imagemergedeventargs/name-property/llms-full.txt) of the placeholder, whether it was [Merged](https://docs.textcontrol.com/tx-text-control-dotnet-winforms/reference/txtextcontrol-documentserver/mailmerge-imagemergedeventargs/merged-property/llms-full.txt) and, for a placeholder in a block, the [MergeBlockName](https://docs.textcontrol.com/tx-text-control-dotnet-winforms/reference/txtextcontrol-documentserver/mailmerge-imagemergedeventargs/mergeblockname-property/llms-full.txt).
- [DescriptiveText](https://docs.textcontrol.com/tx-text-control-dotnet-winforms/reference/txtextcontrol-documentserver/mailmerge-imagemergedeventargs/descriptivetext-property/llms-full.txt) replaces the descriptive text of the merged image, and [Image](https://docs.textcontrol.com/tx-text-control-dotnet-winforms/reference/txtextcontrol-documentserver/mailmerge-imagemergedeventargs/image-property/llms-full.txt) gives access to the image itself.
- [BarcodeMerged](https://docs.textcontrol.com/tx-text-control-dotnet-winforms/reference/txtextcontrol-documentserver/mailmerge/barcodemerged-event/llms-full.txt) occurs after a barcode has been merged. [BarcodeMergedEventArgs](https://docs.textcontrol.com/tx-text-control-dotnet-winforms/reference/txtextcontrol-documentserver/mailmerge-barcodemergedeventargs/llms-full.txt) contains the merged [BarcodeFrame](https://docs.textcontrol.com/tx-text-control-dotnet-winforms/reference/txtextcontrol-documentserver/mailmerge-barcodemergedeventargs/barcodeframe-property/llms-full.txt).

The merged invoice shows the logo in the size of the placeholder and a QR code that encodes *INV-1001*.

### Check Barcode Values

Each barcode type accepts only certain characters and lengths, so a value from the data may not fit. Static methods of `TXBarcodeControl` check a value before the merge:

```csharp
string invoiceNumber = "INV-1001";

if (!TXBarcodeControl.IsTextValid(BarcodeType.QRCode, invoiceNumber, out string errorMessage))
{
    MessageBox.Show(this, "Invalid value: " + errorMessage);
}
```

[IsTextValid](https://docs.textcontrol.com/tx-text-control-dotnet-winforms/reference/txtextcontrol-barcode/txbarcodecontrol/istextvalid-method/llms-full.txt) returns `false` and an error message for a value the type can't encode. [GetMinimumTextLength](https://docs.textcontrol.com/tx-text-control-dotnet-winforms/reference/txtextcontrol-barcode/txbarcodecontrol/getminimumtextlength-method/llms-full.txt) and [GetMaximumTextLength](https://docs.textcontrol.com/tx-text-control-dotnet-winforms/reference/txtextcontrol-barcode/txbarcodecontrol/getmaximumtextlength-method/llms-full.txt) return the lengths a type accepts. [BarcodeType](https://docs.textcontrol.com/tx-text-control-dotnet-winforms/reference/txtextcontrol-barcode/barcodetype/enumeration/llms-full.txt) has 20 types, from one-dimensional codes such as `Code128`, `EAN13` and `UPCA` to two-dimensional codes such as `QRCode`, `Datamatrix` and `PDF417`.

### Merge Charts

A chart in a template can be filled from the data as well: each row of a table becomes a data point, with one column for the label on the axis and one for the value. Charts need the chart package and the references described in [Integrating Charts and Barcodes](https://docs.textcontrol.com/tx-text-control-dotnet-winforms/integration/charts-barcodes/#add-the-chart-control-to-the-project). The examples use this *sales.json*, whose array `country-sales` holds the sales of each country:

```json
[
  {
    "country-sales": [
      { "country": "United States", "sales": 7890567 },
      { "country": "Germany", "sales": 889078 },
      { "country": "Canada", "sales": 3466363 }
    ]
  }
]
```

With *sales.json* loaded into the Reporting tab, for example with **Load JSON File**, users connect a chart to the data:

1. Insert a chart with **Chart** in the **Insert** tab.
2. Select the chart and click **Set Data Relation** in the **Data** group of the chart layout tab, which TX Words shows as **Chart Formatting** in the **Chart Tools** group.
3. In the **Set Chart Data Relation** dialog box, keep the **Main Table**, choose `country-sales` as **Child Table**, `country` for **Axis Labels** and `sales` for **Values**, and click **OK**.

![The Set Chart Data Relation dialog box with the main table RootTable, the child table country-sales, the axis labels column country and the Values drop-down open with country and sales.](https://docs.textcontrol.com/assets/img/tx-text-control-dotnet-winforms/set-chart-data-relation.1c11049f.webp)

The dialog box prepares the chart for the merge: it keeps one chart area and one series, names the chart frame after the child table, the chart area after the column of the axis labels and the series after the column of the values. The merge then fills the chart with one data point per row, shown here in the preview of an older version of TX Words:

![An older version of TX Words with a Preview tab after a merge, showing a doughnut chart with one segment for each country of the data and a legend with the country names.](https://docs.textcontrol.com/assets/img/tx-text-control-dotnet-winforms/chart-merged-preview.29e45050.webp)

In code, [ChartDataRelationDialog](https://docs.textcontrol.com/tx-text-control-dotnet-winforms/reference/txtextcontrol-documentserver-windows-forms/chartdatarelationdialog/llms-full.txt) opens the same dialog box for a chart, and `MailMerge` fills the charts of a template in every merge. Add `using TXTextControl.DataVisualization;` and `using TXTextControl.DocumentServer.Windows.Forms;` to *Form1.cs*:

```csharp
private void chartDataButton_Click(object sender, EventArgs e)
{
    // The chart the user has selected, or null
    ChartFrame chartFrame = textControl1.Charts.GetItem();

    if (chartFrame == null)
    {
        MessageBox.Show(this, "Select a chart first.");
        return;
    }

    using (ChartDataRelationDialog dialog = new ChartDataRelationDialog(
        chartFrame, ribbonReportingTab1.DataSourceManager))
    {
        dialog.ShowDialog(this);
    }
}

private void mergeChartsButton_Click(object sender, EventArgs e)
{
    using (MailMerge mailMerge = new MailMerge { TextComponent = textControl1 })
    {
        mailMerge.ChartMerged += (s, args) =>
            System.Diagnostics.Debug.WriteLine("Chart merged: " + args.ChartFrame.Name);

        mailMerge.MergeJsonData(File.ReadAllText("sales.json"));
    }
}
```

The code works as follows:

- [Charts.GetItem](https://docs.textcontrol.com/tx-text-control-dotnet-winforms/reference/txtextcontrol-datavisualization/chartcollection/getitem-method/llms-full.txt) returns the selected chart as a [ChartFrame](https://docs.textcontrol.com/tx-text-control-dotnet-winforms/reference/txtextcontrol-datavisualization/chartframe/llms-full.txt), or `null`.
- The [ChartDataRelationDialog constructor](https://docs.textcontrol.com/tx-text-control-dotnet-winforms/reference/txtextcontrol-documentserver-windows-forms/chartdatarelationdialog/constructor/llms-full.txt) takes the chart and the `DataSourceManager` whose tables the dialog box lists.
- [ChartMerged](https://docs.textcontrol.com/tx-text-control-dotnet-winforms/reference/txtextcontrol-documentserver/mailmerge/chartmerged-event/llms-full.txt) occurs after each chart has been merged, and [ChartFrame](https://docs.textcontrol.com/tx-text-control-dotnet-winforms/reference/txtextcontrol-documentserver/mailmerge-chartmergedeventargs/chartframe-property/llms-full.txt) of its arguments is the merged chart.

The blog article [Using MailMerge with Chart Objects and JSON Data](https://www.textcontrol.com/blog/2019/07/18/using-mailmerge-with-chart-objects-and-json-data/) builds this template step by step and offers it for download.

### Image Merge Fields

Before named placeholders, images were merged into merge fields whose name starts with `image:`, such as `image:Logo`. Such templates are still merged, but the [ImageFieldMerged](https://docs.textcontrol.com/tx-text-control-dotnet-winforms/reference/txtextcontrol-documentserver/mailmerge/imagefieldmerged-event/llms-full.txt) event that belongs to them is marked obsolete in the assembly, and the compiler warns when your code uses it. Use named placeholders and `ImageMerged` in new templates.

### Next Steps

- [Merge Blocks](https://docs.textcontrol.com/tx-text-control-dotnet-winforms/mail-merge/blocks/llms-full.txt): repeat images and barcodes for each record.
- [Data Sources](https://docs.textcontrol.com/tx-text-control-dotnet-winforms/mail-merge/data-sources/llms-full.txt): the data that carries images and values.
- [Charts and Barcodes](https://docs.textcontrol.com/tx-text-control-dotnet-winforms/document-editor/charts-barcodes/llms-full.txt): charts and barcodes in the editor.
- The blog article [Merging Barcodes with JSON Data in C#](https://www.textcontrol.com/blog/2022/02/14/merging-barcodes-with-json-data-in-csharp/): a QR code filled from JSON data.

---

## Nearby

- **Previous:** [Subtemplates](https://docs.textcontrol.com/tx-text-control-dotnet-winforms/mail-merge/subtemplates/llms-full.txt)
- **Next:** [Conditional Content](https://docs.textcontrol.com/tx-text-control-dotnet-winforms/mail-merge/conditional-content/llms-full.txt)
