Text-Hardcopy

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
Links

Copyright-Bestimmungen: siehe Über diese Seite