itrain-home Kinderpatenschaften mit Plan Deutschland  
home
 Aktuelle Seite:  knowhow sql transfer dts bildimport.asp 
 



 

Import von Bildern (GIF/JPG/BMP) in eine SQL Servertabelle

(inclusive Angabe der Breite und Höhe in Pixeln)

Diese kleine Tutorial zeigt Ihnen, wie Bilddateien (GIFs, JPGs oder BMPs) per DTS in eine SQL Server Tabelle importiert werden können.

Voraussetzugen: SQL Server 2000

Das besondere an diesem Script ist, dass zusätzlich während des Imports die Breite und Höhe des Bildes in Pixeln ermittelt werden und ebenfalls in der Datenbank abgelegt werden.

Die Zieltabelle auf dem SQL Server hat den folgenden Aufbau:

Pfad varchar(255)
Dateiname varchar(128)
  Typ varchar(3)
  Höhe int
  Breite int
  Bild image

Pfad und Dateiname wurden als Primärschlüssel definiert, um doppelte Einträge zu vermeiden und schnell auf ein Bild zugreifen zu können.

Das SQL Script zum Erstellen der Tabelle können Sie auch herunterladen.

Soweit zum Ziel für den Import. Damit nun alle Dateien aus einem Verzeichnis mit den notwendigen Informationen importiert werden können, werden, müssen noch ein paar "kleinere" Probleme gelöst werden.

 

1. Liste der Dateien als Datenquelle

Um ein möglichst einfaches DTS-Paket zu erhalten, sollten die Dateinamen in Tabellenform vorliegen. Dazu gibt es natürlich verschiedene Möglichkeiten. So könnte man zum Beispiel alle Dateinamen zeilenweise in eine Textdatei schreiben und diese dann als Quelle verwenden. Dieser Ansatz ist mit relativ einfachen Mitteln zu realisieren - schöner wäre es jedoch ein direktes Listing der Tabellen zu erhalten.

Nach einigem Suchen stieß ich auf die erweiterte gespeicherte Prozedur xp_dirtree in der master-Datenbank. Diese Prozedur listet standardmäßig alle Unterverzeichnisse für das angegebene Verzeichnis auf. Dabei werden beim einfachen Aufruf alle Ebenen durchsucht.

Durch Angabe eines zweiten Parameters läßt sich die Suchtiefe jedoch einschränken: So listet der Aufruf EXEC master..xp_dirtree 'C:\Daten', 1 nur alle direkten Unterverzeichnisse von C:\Daten auf. Was fehlt sind die Dateinamen. Nach etwas Detektivarbeit mit Hilfe des Profilers (das Ablaufverfolgungstool des SQL Servers) war die Lösung gefunden: Über einen dritten Parameter lassen sich auch alle Dateien listen. Sollen zum Beispiel alle Dateien im Verzeichnis C:\Daten angezeigt werden, kann das folgende Script verwendet werden:

EXEC master..xp_dirtree 'C:\Daten', 1, 1

Als Ergebnis erhält man eine Tabelle mit allen Dateien und Unterverzeichnissen des Ordners C:\Daten. In der Ergebnisspalte File läßt sich ablesen, ob es sich um eine Datei oder ein Verzeichnis handelt.

Mit diesem Hintergrundwissen läßt sich leicht eine gespeicherte Prozedur schreiben, die alle Dateien in einem Verzeichnis zurückliefert:

CREATE PROCEDURE getFileNames
@Folder nvarchar(255) = N'C:\',
@Extension nvarchar(3) = N'GIF'
AS
SET NOCOUNT ON
CREATE TABLE #tempFiles(filename nvarchar(255), depth int, isfile int)
INSERT INTO #tempFiles
   EXEC master..xp_dirtree @folder, 1,2
SELECT filename FROM #tempFiles WHERE isfile = 1 AND RIGHT(filename,3) LIKE @extension

GO

Diese Prozedur kann jetzt einfach aufgerufen werden:

EXEC master..getFileNames 'C:\Daten\Grafik', 'GIF'

Liefert die Namen aller Gif-Dateien im Verzeichnis 'C:\Daten\Grafik' zurück. Beachten muss man natürlich, dass hier der SQL Server direkt auf das Verzeichnis zugreift - es muß also sichergestellt sein, das das Dienstkonto des SQL Servers Lesezugriff auf das Verzeichnis besitzt.

Sie finden dieses Script zum Download unter http://www.itrain.de/knowhow/sql/tsql/xp/getfilenames.asp zum Download.

2. Ermitteln der Breite und Höhe der Bilder in Pixel

Nachdem die Liste der Dateien erstellt ist, bleibt noch das Ermitteln der Breite und Höhe der Bilder. Glücklicherweise bietet VBScript die fertige Funktion LoadPicture, mit der GIF, JPG und BMP Dateien geöffnet werden können. Über die Eigenschaften Width und Height kann dann die Breite und Höhe ermittelt werden. Leider sind diese Größenangaben jedoch nicht in Pixel sondern in OLE_HIMETRIC, also 10tel Milimetern angegeben. Es wird also noch eine Umrechnung zwischen OLE_HIMETRIC nach Pixel benötigt.

Um diese Umrechnung durchführen zu können wird eine weitere Info benötigt: Welche Auflösung (DPI) ist für den Monitor eingestellt? Dieses Rätsel zu lösen war nicht ganz einfach. Zwar gibt es die API-Funktion GetDeviceCaps, mit der die Auflösung ermittelt werden kann, aber leider können API-Aufrufe nicht aus einem Script aufgerufen werden. Eine mögliche Lösung ist die Verwendung der WMI-Daten des Rechners. Falls WMI installiert ist, können fast alle Objekte eines Rechners und deren Eigenschaften abgefragt werden. Nach einigem Suchen im WMI-SDK war eine Lösung gefunden:

Set MonitorInfo = _
GetObject("WINMGMTS:{impersonationLevel=impersonate}!\\.\root\cimv2:Win32_DesktopMonitor.DeviceID=""DesktopMonitor1""")

Über diesen Aufruf werden die Informationen des ersten angeschlossenen Desktop-Monitors in das Objekt MonitorInfo übergeben.

Über die Eigenschaften PixelsPerXLogicalInch und PixelsPerYLogicalInch können dann die horizontale und vertikale Auflösung ermittelt werden. Zur Umrechung kann dann die Formel:

Pixel = OLE_HIMETRIC wert  / (verhältnis_centimeter_inch / DPI)

verwendet werden.

 

3. Der Aufbau des DTS-Pakets

Nachdem die technischen Vorbedingungen geklärt sind, jetzt zum Aufbau des DTS-Pakets.

Für das Paket werden zwei Verbindungen (eine Quelle und ein Ziel) definiert. Für beide Verbindungen wird eine SQL Server Verbindung () verwendet.

Die erste Verbindung sollte nach Möglichkeit auf die master-Datenbank des Servers gerichtet sein. Im Beispiel habe ich sie "master auf (lokal)" genannt.

Die zweiter Verbindung ist eine Verbindung zur Zieldatenbank, in der sich die Tabelle "Bilder" befindet.

Anschließend können die Transformationen zwischen den beiden Verbindungen eingerichet werden.

Auf der Seite Quelle wird die SQL Abfrage "EXEC getFileNames 'D:\Daten\Grafik\', 'GIF' " eingetragen.

(Verwenden Sie für diesen ersten Test ein Verzeichnis, das Bilddateien enthält).

Da die gespeicherte Prozedur getFileNames jedoch die Ergebnisse in einer temporären Tabelle verwaltet hat DTS Probleme die notwendigen Metadaten für die Prozedur zu ermitteln. Falls Sie an dieser Stelle die Schaltfläche "Analysieren" anklicken, erhalten Sie die Fehlermeldung:

Fehlerquelle: Microsoft OLE DB Provider for SQL Server
Ungültiger Objektname: #tempfiles

DTS versucht an dieser Stelle die Metainformationen abzurufen und ruft dazu die Prozedur mit der Anweisung SET FMTONLY ON auf. Dadurch wird aber die Prozedur nicht wirklich ausgeführt; die temporäre Tabelle wird nie erstellt und somit liegen auch keine Metadaten über die Spaltenaufbau vor. Dieses Problem läßt sich aber mit einem kleinen Trick umschiffen (Thanks to SQL Server MVP Umachandar): Durch die Anweisung SET FMTONLY OFF kann DTS überlistet werden. Beim Abrufen der Metadaten wird die Prozedur jetzt tatsächlich ausgeführt und die temporäre Tabelle wird erstellt (und nach Beenden der Prozedur auch wieder gelöscht).

Auf der Seite "Ziel" kann jetzt die Zieltabelle "Bilder" ausgewählt werden.

Bei den Transformationen müssen jetzt die einzelnen Zielspalten gefüllt werden. Die Spalte Dateiname kann direkt aus der Quelle kopiert werden.

Für die Spalten Breite und Höhe wird ein ActiveX-Script benötigt und für die Spalte "Bild" kann eine "Read File"-Transformation eingesetzt werden. Die Spalten Pfad und Typ sollen über globale Paketvariablen gefüllt werden.

Einrichten der Transformationen - Schritt für Schritt

1. Füllen der Spalten Pfad und Dateiname

2. Füllen der Spalten Typ, Breite und Höhe

3. Füllen der Spalte Bild

Festlegen der Paketvariablen

In den Paketeigenschaften können über die Seite "Globale Variablen" die Variablen für das Paket definiert werden. Für dieses Paket sollen vier Variablen festgelegt werden: Der Quellpfad, der gesuchte Dateityp, die vertikale und horizontale Auflösung in DPI. Im Beispiel habe ich die folgenden Variablennamen verwendet:

  • DPIX (vorbelegt mit 96)
  • DPIY (vorbelegt mit 96)
  • Quellpfad (Pfad der durchsucht werden soll)
  • Dateityp (Dateierweiterung für gesuchte Dateien)
  • Definition der Transformationen
  • Dateiname und Pfad übernehmen

Um Dateiname und Quellpfad in einem Schritt zu übernehmen habe ich eine "ActiveX-Script"-Transformation verwendet. Im Script wird die Zielspalte "Dateiname" aus der Quellspalte "Filename" übernommen. Die Zielspalte "Pfad" wird mit dem Inhalt der globalen Variablen "Quellpfad" gefüllt:

Function Main()
   DTSDestination("Pfad").Value = DTSGlobalVariables("Quellpfad").Value
   DTSDestination("Dateiname") = DTSSource("filename")
   Main = DTSTransformStat_OK
End Function

Im nächsten Schritt werden die Breite und Höhe des Bildes ermittelt und in die entsprechenden Zielspalten geschrieben.

Auch hierzu wird ein ActiveX-Script verwendet:

Function Main()
Dim bild
const CENTITOINCH = 2539.68254
  Set bild = LoadPicture(DTSGlobalVariables("Quellpfad").Value & "\" & DTSSource("filename"))
  DTSDestination("Höhe").Value = bild.height / (CENTITOINCH / DTSGlobalVariables("DPIY").Value)
  DTSDestination("Breite").Value = bild.width / (CENTITOINCH / DTSGlobalVariables("DPIX").Value)
  DTSDestination("Typ").Value = lcase(DTSGlobalVariables("Dateityp").Value)
  Set bild=Nothing
  Main = DTSTransformstat_OK
End Function

Als letztes muss nun noch die Spalte "Bild" mit dem Bild gefüllt werden. Dazu wird eine "Read File"-Transformation verwendet. In den Eigenschaften muss hier ein Quellpfad angegeben werden. Da die Zielspalte der Transformation vom Typ "image" ist, spielt die Angabe des Dateityps keine Rolle.

Falls Sie gültige Pfade angegeben haben, kann jetzt schon ein erster Test des Pakets erfolgen.

Zum Abschluss werden jetzt noch die dynamischen Werte richtig gesetzt und die DPI-Auflösung des Monitors ermittelt.

Dazu wird zunächst ein Task vom Typ "Dynamische Eigenschaften" verwendet. Hier wird die Eigenschaft FilePath der vorher erstellten "Read File"-Transformation auf den in der globalen Variablen angegebenen Namen gesetzt.

Anschließend wird ein ActiveX-Task erstellt. Dieses Task dient dazu, die DPI-Auflösung zu ermitteln. Außerdem wird an dieser Stelle noch die SQL-Anweisung für die Ausführung der gespeicherten Prozedur neu generiert (Leider habe ich keine Möglichkeit gefunden, direkt Parameter für diese Prozedur anzugeben.)

Function Main()
Dim MonitorInfo
On Error Resume Next 
Set MonitorInfo = Nothing
Set MonitorInfo = GetObject("WINMGMTS:{impersonationLevel=impersonate}!\\.\root\cimv2:Win32_DesktopMonitor.DeviceID=""DesktopMonitor1""")
If Not MonitorInfo Is Nothing Then
   DTSGlobalVariables("DPIX").Value = MonitorInfo.PixelsPerXLogicalInch
   DTSGlobalVariables("DPIY").Value = MonitorInfo.PixelsPerYLogicalInch
Else ' Just guess:
   DTSGlobalVariables("DPIX").Value = 96
   DTSGlobalVariables("DPIY").Value = 96
End If
DTSGlobalVariables("SQLAnweisung").Value = "SET FMTONLY OFF " & vbcrlf & "EXEC getFileNames '" & _
         DTSGlobalVariables("Quellpfad").Value & "', '" & DTSGlobalVariables("Dateityp").Value & "'"
Main = DTSTaskExecResult_Success
End Function

Im letzten Schritt wird jetzt noch die neu erzeugte SQL EXECUTE Anweisung als SQL-Abfrage für die Datenquelle eingetragen. Dazu wird wieder ein Task vom Typ "Dynamische Eigenschaften" verwendet.

Auf Wunsch können jetzt noch vorhandene Daten gelöscht werden. Dazu wird einfach ein Task vom Typ "SQL ausführen" verwendet.

Das vollständige Paket (incl. Workflow) sieht so aus:

 

Nachdem das DTS-Paket gespeichert wurde können nun die Bilder importiert werden.

Viel Spaß beim Ausprobieren

Fehler gefunden, Anregungen, Kritik? Email an sql@itrain.de!

 

 

 

Leerraum

Dokument zum Drucken anzeigen
English Pages
Link-Tipp zum Thema "Microsoft SQL Server": www.vbxml.com/conference/wrox/2000_vegas/html/content/briank_dts.asp

Umfangreiche Site zu den Themen XML, SQL, ASP.Net etc.