← ST-Computer 09 / 1992

Text-Hardcopy

Programmierpraxis

Hardcopy-Problem auf dem Atari ST (ALT-HELP drücken und sich wundern) ist eigentlich durch eine große Anzahl von Hardcopy-Utilities, Accessories etc. ausreichend gelöst. Warum noch ein weiteres Programm? Alle mir bekannten Hardcopy-Programme arbeiten nach dem gleichen Prinzip: Man kann Teile des Bildschirms (bzw. den ganzen) als Grafik ausdrucken bzw. auf Diskette speichern. Diese Hardcopy-Programme unterscheiden sich lediglich in ihrem Funktionsumfang bzw. ihrer Bedienbarkeit.

Ich fertige Hardcopies normalerweise nur aus dem Grund an, weil mich die Informationen in einem Fenster (Directory, Help-Screen) interessieren. Es kommt dabei nicht auf grafische Qualität der Hardcopy bzw. die Darstellung von Icons etc. an. Eine Grafik-Hardcopy ist in diesem Falle sogar eher als störend zu betrachten; denn Grafikdruck dauert länger als Textdruck, ist in der Qualität durchweg schlechter (zumindest auf normalen Druckern), kostet mehr Farbband und Nerven (Lärm!) etc. Zudem lassen sich Bildausschnitte durchweg schlechter weiterverarbeiten als Texte.

So wurde die Idee geboren, den zu druckenden Text von Grafik in eine ASCII-Datei zu wandeln, die entweder gedruckt oder in Textprogramme übernommen werden kann. Diese Aufgabe sollte eine Art „Mini-OCR“ übernehmen. Die Bezeichnung OCR ist schon fast übertrieben, schließlich sehen auf dem Bildschirm alle Buchstaben gleichen ASCII-Codes auch gleich aus. Auch die Abstände derZeichen voneinander sind klar definiert. Lediglich die Position des Textes auf dem Bildschirm ist frei verschiebbar (Fenster!). Der Abstand der Textzeilen ist davon abhängig, ob der Text in einem Fenster steht (17 Pixel) bzw. auf einem TOS-Screen erscheint (15 Pixel). Diesem Umstand wird bei Programmstart Rechnung getragen, indem das Programm erfragt, ob man ein Fenster (GEM) oder einen Text-Screen (TOS) hardkopieren möchte.

Funktionsweise

Da das Aussehen eines jeden Zeichens genau definiert ist, und auch keine zwei Zeichen identisch aussehen, bietet sich folgendes Vorgehen an: Die Grafikmuster der einzelnen Zeichen (8x16 Pixel, entspricht 38 Byte Grafikdaten in GFA-BASIC) werden in einem String hintereinander gespeichert. Die absolute Position der Grafikdaten entspricht also dem 38-fachen des entsprechenden ASCII-Codes. Durch byteweisen Vergleich mit dem gesuchten Muster kann also das entsprechende Zeichen wiedererkannt werden. Dieser Vergleich geschieht mit der INSTR-Funktion, die die Position eines Strings in einem anderen wiedergibt. Liefert die INSTR-Funktion einen Wert >0, wurde ein bekanntes Grafikmuster gefunden, liefert sie den Wert 0, war das Grafikmuster nicht bekannt. Glücklicherweise ist die Funktion eindeutig definiert, so daß die „Erfolgsrate“ der Mini-OCR bei 100% liegt (es treten keine Scan-Fehler auf).

Voraussetzung für den Scan-Vorgang ist die Kenntnis, wo der Text auf dem Bildschirm beginnt. Diese Position ist bekanntlich ja pixelweise frei verschiebbar. Der Bildschirm wird hierzu innerhalb des in Frage kommenden Bereichs pixelweise abgetastet, bis ein bekanntes Grafikmuster (ein bekanntes Zeichen) gefunden wird. Der nächste Buchstabe steht dann mit Sicherheit 8 Pixel weiter rechts, die nächste Zeile beginnt mit Sicher- heit 15 oder 17 Pixel weiter unten.

So sollte das Gummiband angelegt werden

Vorraussetzungen

In dieser Version läuft das Programm nur in der hohen Auflösung und mit dem aktuellen Systemzeichensatz (8x16 Pixel), d.h. der Atari Standardkonfiguration. Schriftattribute wie fett, kursiv etc. werden nicht erkannt. Diese Einschränkungen sind jedoch sicherlich zu verschmerzen, zumal sie in „normalen“ Fenstern ohnehin nicht verwendet werden. Nicht erkannte Zeichen werden durch ein Space ersetzt.

In der Initialisierungsschleife wird die Mustertabelle für die ASCII-Codes bis 158 angelegt. Die Obergrenze kann willkürlich nach oben gesetzt werden. Aus Geschwindigkeitsgründen habe ich die (selten auftretenden) Zeichen von 158 bis 255 nicht eingeschlossen.

Zeitbedarf

Obwohl das Programm in BASIC geschrieben ist, ist es erstaunlich schnell. Für den Scan-Vorgang werden (je nach Bildgröße) etwa 10-60 Sekunden benötigt. Hierfür entfallen etwa 10 Sekunden auf die Suche nach dem Textanfang. Für eine Scan-Zeile (etwa 60-70 Zeichen) benötigt das Programm jeweils 5-10 Sekunden, so daß keine längeren Wartezeiten auftreten. Rechnet man die Zeitersparnis beim Drucken mit (Texte werden wesentlich schneller gedruckt als Grafik), so dauert die Texthardcopy nicht länger als normaler Grafikdruck. Die Qualität ist aber wesentlich höher (eben NLQ).

Bedienung

Texthardcopy läuft sowohl als Accessory (in THARDCOP.ACC umbennen) als auch als Programm (THARDCOP.PRG). Das Accessory kann durch Anwählen in der Menüleiste bzw. durch Drücken und Halten der beiden Shift-Tasten für ca. 1 Sekunde gestartet werden. Das Programm kann z.B. von einem CLI gestartet werden, wenn man sich in der TOS-Umgebung bewegt. Die verschiedenen Möglichkeiten sind im Listing nochmal ausführlich dokumentiert. Nach dem Programmstart erscheint zunächst eine Dialogbox, in der die Art des Hardcopy-Textes gewählt werden kann (s.o.). Zusätzlich steht ein „HELP“-Button zur Verfügung. Über diesen kann in das Help/Parameter-Menü verzweigt werden. Dort wird ein kurzer Hilfstext ausgegeben. Zusätzlich kann über den Button „Snap“ ein Grafikausschnitt auf Diskette gespeichert werden (Snapshot-Utility). Über den Zeilenabstand-Button können exotische Zeilenabstände gewählt werden. Dieser Button wird bisher nicht benötigt und ist für die Zukunft reserviert, falls Atari ein anderes Ausgabeformat wählt. Nachdem Sie Ihre Wahl getroffen haben, erscheint die Aufforderung „Bereich wählen“. Sie können nun ein Gummiband aufziehen, das den zu scannenden Textbereich umschließt. Das Gummiband sollte so angelegt werden, daß die Ecken jeweils etwa 5 Pixel vom Textrand entfernt sind. Besonders die Wahl der linken oberen Ecke spielt eine große Rolle, da von hier ausgehend der Textanfang gesucht wird. Als Anhalt kann hier Bild 1 dienen. Nun beginnt der eigentliche Scan-Vorgang. Während das Programm den Textanfang sucht (Meldung „Suche Textanfang“), erscheint in der rechten oberen Ecke ein wachsender Balken. Ist der Textanfang gefunden, wird der Text Zeile für Zeile gescannt (Meldung „Scanne Text“). Der wachsende Balken zeigt auch hier das Voranschreiten der Arbeit an. Wenn der Ausschnitt komplett in ASCII-Text gewandelt ist, werden Sie über den Erfolg des Scannens informiert (Meldung „xxx Zeichen erkannt“). Sie können den fertigen Text nun entweder auf den Drucker ausgeben lassen, verwerfen oder auf Diskette speichern. Der Text wird unter dem File-Namen HRDCOPxx.TXT im aktuellen Directory gespeichert und kann weiterverwendet werden.

' Text-Hardcopy '(c) 1.932 MAXON Computer ' $m 33000 ! Speicher reservieren ap_id&=APPL_INIT() ' ' Programm lauft nur in der hohen Auflösung (640x400) und mit ' dem normalen Systemzeichensatz (8x16) Pixel. Attribute, wie ' fett, kursiv etc. werden nicht erkannt... ' ' Das Programm kann auf 3 Arten gestartet werden ' 1. in der Menüleiste anwählen ' 2. durch Drücken und Halten der beiden Shift-Tasten (ca. 1 sec.) ' 3. durch Umbennen in *.PRG und Starten von einer Shell ' CLR charset$ GET 20,0,40,20,backgr$ FOR t|=0 TO 158 ! Zeichentabelle initialisieren TEXT 30,13,CHR$(t|) ! Diese Routine wird nur einmal GET 30,0,36,15,char$ ! beim Booten des Rechners bzw. beim charset$=charset$+char$ ! Start als PRG durchlaufen! NEXT t| ! Die Obergrenze (ASCII 158) kann PUT 20,0,backgr$ ! heraufgesetzt werden. Scan-Vorgang CLR backgr$ ! dauert dann aber länger! IF ap_id&<>0 me_id&=MENU_REGISTER(ap_id&," Texthardcopy ") DO b$=SPACE$(16) ! Ereignispuffer a%=VARPTR(b$) ' ' Timer event (1 sek.) setzen und auf Ereignis warten ' ~EVNT_MULTI(48,0,0,0,0,0,0,0,0,0,0,0,0,0,a%,1000) ' ' Menüleiste abfragen IF ASC(MID$(b$,2,1))=40 ! Accessory angeklickt? hardcpy ENDIF ' r%=BIOS(11,-1) ! Shift-Tasten gedrückt? IF (r% AND 3)=3 hardcpy ENDIF LOOP ! Acc's enden nie ... ELSE hardcpy ! oder als PRG gestartet? END ENDIF PROCEDURE hardcpy SHOWM CLR box_wide,snap!,anz_char%,txt$ ' erst mal ein paar allgemeine Fragen stellen ALERT 2,"Texthardcopy by A.Lauterbach|Wovon soll eine Text-Hardcopy|angefertigt werden ?",1," GEM | TOS | Help ",d% SELECT d% CASE 1 add y%=3 CASE 2 add_y%=1 CASE 3 ALERT 1, "GEM - Hardcopy von Window|TOS - Hardcopy von TOS-Screen |Select - Zeilenabstand wählen|Snap - Snapshotutility", 1, "Okay|Select|Snap", d% IF d%=2 REPEAT ALERT 1,"Zeilenabstand wählen | |Abstand = "+STR$(15+add_y%),2, " « |Okay| » ",d% SELECT d% CASE 1 add_y%=MAX(add_y%-1,0) CASE 3 add_y%=MIN(add_y%+1,5) ENDSELECT UNTIL d%=2 ELSEIF d%=3 snap!=TRUE ! Snapshot-Utility ENDIF ENDSELECT DEFMOUSE 3 ' Rubberband darstellen GET 400,0,639,20,backgr$ TEXT 450,15,"Bereich wählen" REPEAT MOUSE xa%,ya%,mk% UNTIL mk%<>0 GRAPHMODE 3 nxa%=xa% nya%=ya% REPEAT MOUSE xe%,ye%,mk% IF ((xe%<>nxa%)+(ye%<>nya%))*(xe%>xa%)*(ye%>ya%) BOX xa%,ya%,xe%,ye% BOX xa%,ya%,nxa%,nya% nxa%=xe% nya%=ye% ENDIF UNTIL mk%=0 ' BOX xa%,ya%,xe%,ye% IF snap!=TRUE ! Snapshot-Utility GET xa%,ya%,xe%,ye%,graf$ HIDEM f$="HRDCPY" vernr%=1 WHILE EXIST (f$+STRS(vernr%)+".OBJ") ! und die Früchte der INC vernr% ! Arbeit verewigen WEND OPEN "O",#1,f$+STR$(vernr%)+".OBJ" PRINT #1,graf$; CLOSE #1 SHOWM ELSE GRAPHMODE 0 BOX 600,2,632,18 HIDEM ' Textanfang suchen (dauert etwa 1-10 sec.) TEXT 450,15,"Suche Textanfang" ya%=MAX(ya%-3,0) FOR x_ofs%=xa% TO xa%+15+add_y% PBOX 616+(xa%-x_ofs%),2,616-(xa%-x_ofs%),18 FOR y_ofs%=ya% TO ya%+15+add_y% GET x_ofs%,y_ofs%,x_ofs%+6,y_ofs%+15,char$ char%=INSTR(charset$,char$) DIV 38 ! bekanntes Textmuster? EXIT IF char%<>0 AND char%<>32 ! Text gefunden NEXT y_ofs% EXIT IF char%<>0 AND char%<>32 ! und raus hier... NEXT x_ofs% start_x%=x_ofs% ! Textanfang TEXT 450,15," Scanne Text" ! jetzt geht's los DEFFILL 1,0 PBOX 600,2,632,18 DEFFILL 1,2,8 REPEAT REPEAT PBOX 617+box_wide,2,616-box_wide,18 ! eine Zeile scannen GET x_ofs%,y_ofs%,x_ofs%+6,y_ofs%+15,char$ char%=INSTR(charset$,char$) DIV 38 ! Zeichen bekannt? IF char%>0 INC anz_char% txt$=txt$+CHR$(char%) ! Zeichen merken ELSE txt$=txt$+" " ENDIF ADD x_ofs%,8 UNTIL x_ofs%>xe% ! Zeilenende? x_ofs%=start_x% ADD y_ofs%,15+add_y% ! neue Zeile suchen ADD box_wide,(15+add_y%)/((ye%-ya%)/(15+add_y%)) txt$=txt$+CHR$(13)+CHR$(10) UNTIL y_ofs%>ye% ! fertig ... DEFMOUSE 0 SHOWM PUT 400,0,backgr$ ! Bild restaurieren ALERT 2, "Es wurden "+STR$(anz_char%)+" Zeichen|erkannt! Wohin damit ?",1, "Drucker|Disk|Müll",d% IF d%=1 LPRINT txt$ ELSE IF d%=2 f$="HRDCPY" vernr%=1 WHILE EXIST (f$+STR$(vernr%)+".TXT" ) ! und die Früchte der INC vernr% ! Arbeit verewigen WEND OPEN "O",#1,f$+STR$(vernr%)+".TXT" PRINT #1,txt$ CLOSE #1 ENDIF ENDIF CLR backgr$,graf$ RETURN
Andreas Lauterbach