Direkt zum Hauptinhalt

Datensatz-Bilder aus cobra einbetten

Dieses Skript zeigt, wie Bilder, die direkt im cobra-Datensatz gespeichert sind (z.B. durch das Mobile CRM), in eine Dokumentausgabe eingebettet werden können.

 



Anwendungsfall

In cobra können Datensätze ein Bild enthalten (z.B. Unterschriften, Fotos, Logos). Dieses Bild soll automatisch in das generierte Dokument eingefügt werden - etwa eine digitale Unterschrift auf einem Protokoll oder ein Produktfoto auf einem Datenblatt.

 



Konfiguration in PRINT+PLUS

  • Exporter-Typ: Dokument-Exporter (Word, Excel)
  • Event: AfterLoadData
  • Platzhalter in der Vorlage: {Präfix.Unterschrift#BildAbsolut} 

 



Funktionsprinzip

  1. Das Bild wird aus der cobra-internen IMAGES-Tabelle gelesen (Binärdaten)
  2. Die Bilddaten werden temporär als Datei auf der Festplatte gespeichert
  3. Der Dateipfad wird als Custom Value bereitgestellt
  4. In der Vorlage wird über das #BildAbsolut-Kommando der Pfad als eingebettetes Bild interpretiert

 



Vollständiges Skript (Current-Datensatz)

// Version 6
namespace Ruthardt.PrintPlus.Skripting
{
	using System;
	using System.Data;
	using System.Data.SqlClient;
	using System.IO;
	using System.Linq;
	using Cobra.Common.Database.BusinessObjects.Schema;
	using Ruthardt.CobraBase.Functions.Access.Ado;
	using Ruthardt.Common.Util;
	using Ruthardt.PrintPlus.Model.Interfaces;

	public class BildEinbetten : IScriptAction
	{
		public void Execute(IPrintContext printContext, ICurrentContext currentContext, IChildContext childContext)
		{
			var datensatz = currentContext.Data;
			var tableId = GetLegacyTableId(datensatz);

			// Bild aus der cobra IMAGES-Tabelle laden
			var sql = "SELECT IMAGEDATA FROM IMAGES WHERE SUPERID = @superid AND TABLEID = @tableid";
			var imageResult = printContext.AdoAccess.GetTable(sql,
				new SqlParameter("@superid", datensatz.CurrentKey),
				new SqlParameter("@tableid", tableId));

			if (imageResult.Rows.Count == 0)
			{
				// Kein Bild vorhanden -> leeren Custom Value setzen (Platzhalter bleibt leer)
				currentContext.CustomValues["Unterschrift"] = "";
				return;
			}

			// Binärdaten als temporäre Datei speichern
			var bildDaten = imageResult.Rows[0][0] as byte[];
			var tempPfad = Path.GetTempFileName();
			File.WriteAllBytes(tempPfad, bildDaten);

			// Pfad als Custom Value bereitstellen
			currentContext.CustomValues["Unterschrift"] = tempPfad;

			printContext.Logger.Debug($"Bild eingefügt: {tempPfad}");
		}

		private static int GetLegacyTableId(IObjectView objectView)
		{
			var tableLogicalName = objectView.ObjectViewInfo.LogicalName;
			if (!Enum.TryParse<APTableTypeOld>(tableLogicalName, out var enumValue))
			{
				throw new InvalidOperationException(
					$"Die Tabelle '{objectView.ObjectViewInfo.UserLevelName}' ({tableLogicalName}) konnte nicht bestimmt werden.");
			}
			return (int)enumValue;
		}
	}
}

Verwendung in der Vorlage

In der Word-Vorlage den Platzhalter mit dem Bild-Kommando verwenden:

<<Current.Unterschrift#BildAbsolut>>

PRINT+PLUS erkennt am #BildAbsolut-Suffix, dass der Wert ein Dateipfad zu einem Bild ist, und fügt dieses direkt in das Dokument ein.


Variante: Bilder aus Child-Datensätzen (Unterdatensätze)

Auch bei Unterdatensätzen können Bilder geladen werden – z. B. Unterschriften in einem Protokoll mit mehreren Abarbeitungsschritten:

// Version 6
namespace Ruthardt.PrintPlus.Skripting
{
	using System;
	using System.Data;
	using System.Data.SqlClient;
	using System.IO;
	using System.Linq;
	using Cobra.Common.Database.BusinessObjects.Schema;
	using Ruthardt.PrintPlus.Model.Interfaces;

	public class ChildBilderEinbetten : IScriptAction
	{
		public void Execute(IPrintContext printContext, ICurrentContext currentContext, IChildContext childContext)
		{
			var children = currentContext.ChildContextByPrefix["TicketAbarbeitung"];
			if (children == null || !children.Any())
			{
				return;
			}

			var tableId = GetLegacyTableId(children.First().Data);

			foreach (var abarbeitung in children)
			{
				var sql = "SELECT IMAGEDATA FROM IMAGES WHERE SUPERID = @superid AND TABLEID = @tableid";
				var imageResult = printContext.AdoAccess.GetTable(sql,
					new SqlParameter("@superid", abarbeitung.Data.CurrentKey),
					new SqlParameter("@tableid", tableId));

				if (imageResult.Rows.Count == 0)
				{
					abarbeitung.CustomValues["Unterschrift"] = "";
					continue;
				}

				var bildDaten = imageResult.Rows[0][0] as byte[];
				var tempPfad = Path.GetTempFileName();
				File.WriteAllBytes(tempPfad, bildDaten);

				abarbeitung.CustomValues["Unterschrift"] = tempPfad;
				printContext.Logger.Debug($"Child-Bild eingefügt für ID {abarbeitung.Data.CurrentKey}: {tempPfad}");
			}
		}

		private static int GetLegacyTableId(IObjectView objectView)
		{
			var tableLogicalName = objectView.ObjectViewInfo.LogicalName;
			if (!Enum.TryParse<APTableTypeOld>(tableLogicalName, out var enumValue))
			{
				throw new InvalidOperationException(
					$"Die Tabelle '{objectView.ObjectViewInfo.UserLevelName}' ({tableLogicalName}) konnte nicht bestimmt werden.");
			}
			return (int)enumValue;
		}
	}
}

In der Vorlage verwenden Sie dann im Child-Bereich: {Präfix.Unterschrift#BildAbsolut}

 



Erklärung

  • IMAGES-Tabelle: cobra speichert Datensatzbilder in einer internen Tabelle IMAGES mit den Spalten SUPERID (Datensatz-ID), TABLEID (Tabellen-ID) und IMAGEDATA (Binärdaten).
  • GetLegacyTableId: Ermittelt die numerische Tabellen-ID über die cobra-interne Enum APTableTypeOld. Dies ist nötig, da die IMAGES-Tabelle alle Bilder aller Tabellen enthält.
  • Temporäre Datei: Die Bilddaten werden als Temp-Datei gespeichert, da PRINT+PLUS einen Dateipfad erwartet (nicht Binärdaten direkt).

 



Hinweise

Bildformat: cobra speichert Bilder als Bitmap-Binärdaten. Die meisten Bildformate (PNG, JPEG, BMP) werden unterstützt.

Leere Bilder: Setzen Sie den Custom Value auf einen leeren String (""), wenn kein Bild vorhanden ist. So bleibt der Platzhalter in der Vorlage leer, ohne einen Fehler zu verursachen.

Temp-Dateien: Die temporären Dateien werden vom Betriebssystem automatisch aufgeräumt. Bei sehr großen Serienexporten kann es sinnvoll sein, die Dateien im AfterLastDocument-Event manuell zu löschen.