Entwickler-Ecke

Basistechnologien - Clipboard -> verarbeiten


BlackMatrix - Mo 12.07.10 19:11
Titel: Clipboard -> verarbeiten
Hallo.

Ein Programm sendet mir meinen zu verarbeitenden string scheinbar nur über die Zwischablage.
Das wäre soweit kein Problem, diesen string nun zu verarbeiten, aber es kann passieren, dass das Programm mehrmals (zur gleichen Zeit oder kurz hintereinander) augerufen wird und die Zwischenablage dann ungeeignet wird, da dort nur jeweils ein string abgelegt werden kann.

Wie erreiche ich nun, dass diese strings korrekt weiterverarbeitet werden können?

Ich hoffe es ist verständlich,ich kann gerne das Programm nennen, aber ich denke das sorgt nur für mehr Verwirrung und ich bekomme gar keine Antwort :(

MfG BlackMatrix


Christian S. - Mo 12.07.10 19:17

user profile iconBlackMatrix hat folgendes geschrieben Zum zitierten Posting springen:
Ich hoffe es ist verständlich,ich kann gerne das Programm nennen, aber ich denke das sorgt nur für mehr Verwirrung und ich bekomme gar keine Antwort :(

Ich denke, da das Hauptproblem in diesem Programm liegt, kann es nur nützen, wenn Du das Programm nennst.


BlackMatrix - Mo 12.07.10 19:22

FineReader 8.0 mit folgendem Aufruf:

Zitat:
"C:\ABBYY FineReader 8\fineocr.exe" "kontoauszug.png" /lang Deutsch /send clipboard"


Christian S. - Mo 12.07.10 19:25

Hm. Wäre es möglich, das Programm dazu zu veranlassen, die Texte in Textdateien zu speichern? Die dann bei jeder Instanz natürlich anders heißen müsste.

Sonst kannst Du nur die Zwischenablage in Deinem Programm überwachen und hoffen, dass Dein Programm schneller lesen als Abby schreiben kann ;-)


BlackMatrix - Mo 12.07.10 19:45

Ich habe versucht mit
Zitat:
/send clipboard>ausgabe.txt
die Textdatei zu erzeugen, aber es wird nur eine leere Textdatei erzeugt. Ich nehme an, dass die Textdatei zu zeitig erzeugt wird, und dadurch leer bleibt.

Ich kann aber z.B. auch
Zitat:
/send MSWord
als Übergabewert angeben, dann wird MSWord geöffnet mit dem enthaltenen string.

Hier noch ein Auszug aus der Command Line.txt von FineReader

Zitat:
SendTarget - the name of the application into which FineReader must send the recognition results. ABBYY FineReader 8.0 can save recognition results in the following formats:
- MSWord - Microsoft Word
- MSExcel - Microsoft Excel
- WordPro - Lotus Word Pro
- WordPerfect - Corel WordPerfect
- StarWriter - Sun StarWriter
- Mail application - Mail Application in MSWord format
- Clipboard - Clipboard
- WebBrowser - Default Web Browser
- Acrobat - Adobe Acrobat
- PowerPoint - Microsoft PowerPoint


jaenicke - Mo 12.07.10 22:13

Versuch doch mal den Webbrowser. Da muss das doch in eine temporäre Datei gespeichert werden, die du dann einfach auslesen kannst. :idea:

user profile iconBlackMatrix hat folgendes geschrieben Zum zitierten Posting springen:
die Textdatei zu erzeugen, aber es wird nur eine leere Textdatei erzeugt. Ich nehme an, dass die Textdatei zu zeitig erzeugt wird, und dadurch leer bleibt.
Das hat damit nix zu tun. Du leitest so nur die Standardausgabe in die Textdatei um. Wenn das Programm aber keine Konsolenausgaben macht (warum sollte es auch?), dann kommt da nix an und die Datei bleibt leer. ;-)


BlackMatrix - Mo 12.07.10 23:04

Bei dem Webbrowser wird auch wie bei den ganzen anderen Varianten, die es gibt, ein Programm geöffnet, was unerwünscht ist. Ich könnte zwar die Prozesse killen, aber wenn ich Firefox kille, dann sind auch meine anderen Fenster weg.

Kann ich mit dem Standardoutput irgendetwas anfangen? Hab da bisher noch keine Erfahrung, aber ich habe mir mal folgendes gecodet:


C#-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
            Process finereader = new Process();
            finereader.StartInfo.UseShellExecute = false;
            finereader.StartInfo.RedirectStandardOutput = true;
            finereader.StartInfo = new ProcessStartInfo("fineocr.exe");
            finereader.StartInfo.Arguments = "\"E://kontoauszug.png\" /lang Deutsch /send clipboard";
            finereader.StartInfo.WorkingDirectory = "C://ABBYY FineReader 8";
            finereader.Start();
            StreamReader sr = finereader.StandardOutput;


Und bekomme eine InvalidOperationException:
Zitat:
StandardOut wurde nicht umgeleitet, oder der Prozess wurde noch nicht gestartet.


Außerdem bekomme ich, wenn ich anstatt

C#-Quelltext
1:
finereader.StartInfo = new ProcessStartInfo("fineocr.exe");                    


C#-Quelltext
1:
finereader.StartInfo.FileName="FineOCR.exe";                    

verwendet, die Exception, dass
Zitat:
Das System kann die angegebene Datei nicht finden


jaenicke - Di 13.07.10 02:24

user profile iconBlackMatrix hat folgendes geschrieben Zum zitierten Posting springen:
Kann ich mit dem Standardoutput irgendetwas anfangen?
Wie gesagt:
user profile iconjaenicke hat folgendes geschrieben Zum zitierten Posting springen:
Wenn das Programm aber keine Konsolenausgaben macht (warum sollte es auch?), dann kommt da nix an


user profile iconBlackMatrix hat folgendes geschrieben Zum zitierten Posting springen:
dass
Zitat:
Das System kann die angegebene Datei nicht finden
Du hast auch vergessen den Pfad anzugeben. ;-)
// EDIT: Oops, hab den Pfad übersehen.


BlackMatrix - Di 13.07.10 02:34

Den Pfad habe ich doch mit

C#-Quelltext
1:
finereader.StartInfo.WorkingDirectory = "C://ABBYY FineReader 8";                    


angegeben oder etwa nicht? Wie gesagt, ich tausche nur die beiden Zeilen im vorletzten Post miteinander aus. Sollten die nicht beide funktionieren?

Aber wenn du sagst, dass das mit dem stdout eh nicht funktionieren wird, dann hat sich das ja auch schon erledigt.

Und wie schaut es aus, wenn FineReader die Ausgabe an MSWord oder StarWriter macht, dann muss es ja auch irgendwie die Informationen senden. Kann man die nicht irgendwie abfangen?

Oder eben die Methode von oben, ein Programm, dass vorgaukelt das Programm zu sein, was der FineReader öffnen will, aber eben doch nur eine .txt Datei erzeugt.


Trashkid2000 - So 25.07.10 21:02

Hallo BlackMatrix,

hast Du denn schon eine Lösung für Dein Problem gefunden?

Habe mich mal ein bisschen mit dem Problem auseinander gesetzt. Also, Abbyy erstellt bei der OCR-Erkennung einen Ordner im Temp-Verzeichnis, der denn FineOCRx heißt. X ist eine Nummer, die die Anzahl der OCR-Texterkenungs-Prozesse beschreibt. Also Prozess 1 Nummer 0, Prozess 2 Nummer 1 usw.. In diesem Ordner sind Dateien, die temporär benutzt werden und u.a. die Konfiguration enthält.

So, nachdem die Verarbeitung beendet ist, wird das Ergebnis erzeugt. Habe mal den Output in Form von einer html- Datei erzeugt. Das Problem ist einfach, dass der Name der Temp- Datei des Ergebnisses dynamisch erzeugt wird, und nicht vorher abgefragt werden kann. Also habe ich einen FileSystemWatcher angesetzt, der das Temp- Verzeichnis überwacht und anschlägt, wenn die Temp- Datei erstellt wurde. Dann kille ich den Prozess, damit das Standardprogramm nicht geöffnet wird, und könnte dann also das Ergebnis auslesen und weiterverarbeiten.

Ich poste einfach mal den Code

C#-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
35:
36:
37:
38:
39:
40:
    public class OCRReader
    {

        public string FileName { get; private set; }

        Process p;

        public OCRReader(string fileName)
        {
            this.FileName = fileName;
        }

        public void ReadOCR()
        {
            p = new Process();
            p.StartInfo.WorkingDirectory = @"C:\Programme\ABBYY FineReader 8.0 Professional Edition";
            p.StartInfo.FileName = "FineOCR.exe";
            p.StartInfo.Arguments = string.Format("{0} /send WebBrowser "this.FileName);
            p.StartInfo.WindowStyle = ProcessWindowStyle.Hidden;
            p.Start();
            
            FileSystemWatcher watcher = new FileSystemWatcher(Path.GetTempPath());
            watcher.EnableRaisingEvents = true;
            watcher.IncludeSubdirectories = true;
            watcher.Created += new FileSystemEventHandler(watcher_Created);

            p.WaitForExit();
        }

        private void watcher_Created(object sender, FileSystemEventArgs e)
        {
            Regex regex = new Regex(@"tmp.+?.htm");

            if (regex.IsMatch(e.Name))
            {
                //do anything with the file
                p.Kill();
            }
        }
    }


Probleme:

- Temp-Ordner FineOCRx wird nach dem killen nicht gelöscht - also müsste das händisch gemacht werden
- wenn mehrere Prozesse der OCR aktiv sind, wird dann die richtige Temp-Datei erkannt?
- wie soll dann die Temp- Datei ausgelesen werden?

habe ich noch was vergessen?

Anmerkungen:

- mit der Zwischenablage ist echt nicht wirklich toll, da bei mehreren Prozessen Probleme auftreten
- wenn die Anwendung, die für die Erzeugung des Output nicht installiert ist, wird mal gar kein Output erstellt!


So, soviel erstmal, bin mal gespannt, ob Du schon weiter gekommen bist!

Viele Grüße, Marko


BlackMatrix - Mo 26.07.10 14:16

Jap, bin weitergekommen. Ich habe trotzdem die Zwischenablage benutzt, da mir andere Möglichkeiten einfach zu kompliziert gewesen sind in mein Programm zu implementieren.

Ich habe jedoch 2 "Sicherheitsmechanismen" eingebaut, sodass der FineReader in 99,9% der Fälle mit der Zwischenablage funktioniert.

1. habe ich dafür gesorgt, dass der Programmteil, indem der FineReader arbeitet gelockt ist und nur 1 Thread drauf zugreifen darf:


C#-Quelltext
1:
2:
3:
4:
5:
6:
            lock (this)
            {
                finereader.Start();
                finereader.WaitForExit();
                return Clipboard.GetText();
            }


Und dann kannst du noch als 2. Schutzmechanismus prüfen, ob die FineOCR.exe gerade auf deinem OS läuft um externe Programme zu prüfen.


C#-Quelltext
1:
2:
            while (Process.GetProcessesByName("FineOCR").Length > 0)
                Thread.Sleep(1000);


Das dürfte so gut wie alle Fälle abblocken.


BlackMatrix - Sa 20.11.10 13:15

Hast du hier zufällig weitergemacht?

Ich will nun auch eine andere Möglichkeit implementieren, weil mir die Clipboardsache beim normalen arbeiten richtig auf den Sack geht.

Ich habe deinen Code mal eingebunden und habe gemerkt, dass da noch einiges nicht so rund läuft.

ReadOCR ist fertig, das normale Programm läuft weiter, aber der Watcher ist noch gar nicht fertig.
Die Option /send Webbrowser macht zwar eine schöne temporär Datei, die man abrufen könnte und danach sofort wieder löscht, aber dadurch, dass die Datei im Firefox geöffnet wird, kannst du sie erst löschen, wenn du den Firefox schließt oder besser, gar nicht erst den Firefox öffnen lässt.
Mich würde das insofern nicht stören, wenn der Firefox schon offen ist und nur ein neuer Tab geöffnet wird. Ist der Firefox jedoch nicht geöffnet, müsste man diesen Prozess killen.

Also mir alles bisschen zu unsauber, gibt es irgendeine OCR Alternative, die ich gut im C# einbinden kann?


Trashkid2000 - So 21.11.10 12:33

Hallo,

eigentlich habe ich das Ganze nicht mehr wirklich weiterverfolgt. Aber fand das Thema auch spannend, sodass ich nun nochmal geschaut habe. Und ja, die Idee mit dem FileSystemWatcher war vielleicht nicht die Beste. Aber na ja.

Also, es gibt da eine Open-Source-Alternative: tesseract-ocr
Die Url:
http://code.google.com/p/tesseract-ocr/downloads/list
Ist ein Kommandozeilenprogramm, der Aufruf ist wie folgt:

Quelltext
1:
tesseract.exe "C:\Temp\DemoPhoto.JPG" "C:\Temp\output.txt" -l eng                    
Oder halt der Aufruf aus C#:

C#-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
Process p = new Process();
ProcessStartInfo info = new ProcessStartInfo();
info.FileName = "C:\\Programme\\Tesseract-OCR\\tesseract.exe";
info.Arguments = "\"C:\\Temp\\DemoPhoto.JPG\" \"C:\\Temp\\output.txt\" -l eng";
info.UseShellExecute = false;
info.CreateNoWindow = true;
p.StartInfo = info;
p.Start();
p.WaitForExit();

Die Ergebnisse sind meines Erachtens wirklich gut. Aber die Ausgabe ist halt in einer .txt, also bis auf Zeilenumbrüche keine wirkliche Formatierung. Aber wenn es nur darum geht, Text zu erfassen...

Achso, es gibt wohl auch einen Wrapper für .Net, aber der ist bei mir immer ohne jegliche Fehlermeldung abgeschmiert. Keine Ahnung, warum :?

LG, Marko


BlackMatrix - So 21.11.10 13:50

Du bist genial :]

Dieses Tesseract ist schön kompakt und macht es trotzdem recht gut. Ich hatte es sogar schon installiert, aber als ich gelesen habe, dass es eines der führenden Produkte vom Jahre 1996 bis 2005 war, kam mir das ganze so vor, als sei es 2010 kein Programm mehr, dass man empfehlen sollte. Die Möglichkeit der Kommandozeile reicht mehr dabei erstmal aus.

Vielen Dank dafür.

Mal noch ne Frage.

Worin liegt denn der Unterschied

zwischen

C#-Quelltext
1:
p.StartInfo.WindowStyle = ProcessWindowStyle.Hidden;                    

und

C#-Quelltext
1:
p.StartInfo.CreateNoWindow= true;                    


Achja und was hat die "-1" bei den Argumenten zu sagen :]


Trashkid2000 - So 21.11.10 18:31

user profile iconBlackMatrix hat folgendes geschrieben Zum zitierten Posting springen:
Du bist genial :]

Danke Dir :)

user profile iconBlackMatrix hat folgendes geschrieben Zum zitierten Posting springen:
Worin liegt denn der Unterschied
zwischen

C#-Quelltext
1:
p.StartInfo.WindowStyle = ProcessWindowStyle.Hidden;                    

und

C#-Quelltext
1:
p.StartInfo.CreateNoWindow= true;                    

Nunja, gute Frage!
Also, bei CreateNoWindow=true werden, wenn der Process aus einer Konsolenanwendung gestartet wird, die Ausgaben des Processes in der Konsolenanwendung ausgegeben (wenn sie denn nicht umgelenkt werden). Es wird also kein neues Fenster erzeugt. Wo die Ausgaben hingepackt werden, wenn der Process aus einer GUI gestartet wird, weiss ich nicht. Will ich aber jetzt auch nicht ausprobieren.
Gut, und bei WindowStyle mit Hidden wird zwar das neue Fenster erzeugt, aber nicht angezeigt.

user profile iconBlackMatrix hat folgendes geschrieben Zum zitierten Posting springen:
Achja und was hat die "-1" bei den Argumenten zu sagen :]

Das ist keine "Eins", sondern ein "L" für language. Sieht man manchmal nicht so gut. Auf der DL-Seite gibt es ja versch. Sprachdaten. Aber für was die genau sind!?

LG, Marko


jaenicke - So 21.11.10 18:34

user profile iconTrashkid2000 hat folgendes geschrieben Zum zitierten Posting springen:
Auf der DL-Seite gibt es ja versch. Sprachdaten. Aber für was die genau sind!?
Eine Texterkennung funktioniert in der Regel wie eine Spracherkennung unter anderem über ein Wörterbuch bzw. bekannte häufige Buchstabengruppen. Damit lässt sich die Erkennungsgenauigkeit deutlich steigern, da man dann die Wörter als ganzes analysieren kann und nicht ausschließlich einzelne Buchstaben.

Logischerweise muss man dafür aber wissen um welche Sprache es sich denn handelt.


BlackMatrix - So 21.11.10 19:52

Sind die Argumente der Sprache optional?

Kann man die Auflistung der Argumente irgendwo nachlesen?

Außerdem wäre es noch sehr schön, wenn man die OCR irgendwie konfigurieren könnte, dass z.B. nur Zahlen oder nur Buchstaben gelesen werden.

MfG


Trashkid2000 - Mo 22.11.10 08:15

Ja, die Angabe der Sprache ist optional.

Auflistung der Argumente: einfach tesseract.exe aus cmd aufrufen, dann steht dort:

Quelltext
1:
Usage:tesseract imagename outputbase [-l lang] [configfile [[+|-]varfile]...]                    

Also ich glaube, man kann das Ganze konfigurieren, weswegen auch oben was von configfile steht. Im Unterordner \tessdata\configs sind z.B. versch. Konfigurationsdateien, eine davon heißt "digits".
Sieht so aus, als ob man die nur mit übergeben muss, und dann nur Zahlen bei der Erkennung berücksichtigt werden.

LG, Marko