#!/usr/bin/perl

########################################################################
# This program is free software; you can redistribute it and/or modify #
# it under the terms of the GNU General Public License as published by #
# the Free Software Foundation; either version 2 of the License, or    #
# (at your option) any later version.                                  #
#                                                                      #
# This program is distributed in the hope that it will be useful,      #
# but WITHOUT ANY WARRANTY; without even the implied warranty of       #
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the         #
# GNU General Public License for more details at http://www.gnu.org    #
########################################################################


use constant VERZE => '1.1';   #verze programu
use constant MIN_VYSKA => 10;  #minimalni vyska titulku v pixelech,
			       #pouziva se pro svazani diakritiky s pismeny pri
			       #nacitani pixelovych radku pro 1 txt radek titulku
use constant BOD => '#';       #reprezentace viditelneho pixelu v titulku
use constant MAX_DIAKR => 3;   #maximalni vertikalni vzdalenost hacku,carek,tecek 
			       #od pismene v prazdnych pixelech
			       #plati i pro dvojtecku,strednik,vykricnik,otaznik !!!
			       #pokud chybi diaktirika, tak zvetsit, kdyz je moc
			       #spojenych znaku, tak zkusit snizit
use constant MIN_MEZERA => 6;  #minimalni sirka mezery mezi slovy v pixelech - POZOR
			       #na kurzivu!!!
use constant MAX_PRES => 4;    #maximalni prekryv sousednich znaku pri kurzive v pixelech
			       #vyuziva se pro zachovani diakritiky nad u,y,U,Y,N
use constant RADEK_TERM => 80; #sirka radku terminalu ve znacich pro vypis titulku

#use diagnostics;

use locale; #je to nutne?
use Getopt::Std;

&getopts( "hvo:c:d:g:e:l:s:w:qr" );

#volby programu:
#-h        help
#-v        version
#-o nazev  output - moznost zadat nazev vystupniho souboru SRT titulku
#-c cislo  character - minimalni vyska textu v pixelech - prebije MIN_VYSKA
#-d cislo  distance - maximalni vertikalni vzdalenost diakritiky a tecek od znaku
#-g cislo  gap - minimalni sirka mezery mezi slovy v pixelech
#-e cislo  over - maximalni prekryv sousednich znaku pri kurzive v pixelech
#-l nazev  load - nacteni OCR databaze pred zapocetim rozpoznavani
#-s nazev  save - ulozeni OCR databaze po ukonceni rozpoznavani
#-w cislo  width - sirka okna terminalu ve znacich - aby byl vypis na 1 radek
#-q        quiet - tichy rezim, kdy se nic nevypisuje - pro GUI  ! TO DO !
#-r        recognized - vytiskne navic presnou podobu rozpoznaneho znaku

#===============================================================================
#                 HLAVNI PROGRAM
#===============================================================================

%ocr_databaze = ();

#def %ocr_databaze - uchovava vzory rozpoznanych znaku; hash pouziva jako klice
#		     cislo tvorene sumou cisel ziskanych prevodem jednotlivych
#		     bit-vektoru rozpoznaneho znaku po 8mi bitech na decimalni cislo 0-255

if ( $opt_l ) { &nacti_ocr_databazi; }

if ( $opt_c ) { $min_pixel_vyska = $opt_c; }
  else { $min_pixel_vyska = MIN_VYSKA; }

if ( $opt_d ) { $max_pixel_vzdalenost_diakr = $opt_d; }
  else { $max_pixel_vzdalenost_diakr = MAX_DIAKR; }

if ( $opt_g ) { $min_sirka_mezery = $opt_g; }
  else { $min_sirka_mezery = MIN_MEZERA; }

if ( $opt_e ) { $max_prekryv = $opt_r; }
  else { $max_prekryv = MAX_PRES; }

if ( $opt_w ) { $sirka_radku_terminalu = $opt_w; }
  else { $sirka_radku_terminalu = RADEK_TERM; }


if ( $opt_h ) { &napoveda; }
elsif ( $opt_v ) { &verze; }
elsif ( not $ARGV[0] ) { 
    die "Nebyl zadan zadny .srtx soubor ke zpracovani, viz pgm2srt -h\n"; }
else {

    &prochazej_srtx_soubor_titulku;    

if ( $opt_s ) { &uloz_ocr_databazi; }

}
#-------------------------------------------------------------------------------



#===============================================================================
#                 PODPROGRAMY
#===============================================================================


#===============================================================================
sub prochazej_srtx_soubor_titulku {


    open( ZDROJ_SRTX, "$ARGV[0]" ) or die ("Nemohu otevrit soubor \'$ARGV[0]\'!\n");

    if ( $opt_o ) {
	open( NOVY_SRT, ">$opt_o") or die ("Nemohu zalozit soubor \'$opt_o\'!\n");
    } else {
	open( NOVY_SRT, ">$ARGV[0].new") or die ("Nemohu zalozit soubor \'$ARGV[0].new\'!\n");
    }

    while ( $srtx_radek = <ZDROJ_SRTX> ) {

	chomp($srtx_radek);
	if ($srtx_radek) {

	    unless ( $srtx_radek =~ /^\s*\d+\s*$/ ) {
		close (ZDROJ_SRTX);
		close (NOVY_SRT);
		die ("Vstupni soubor nema format SRT titulku!!!\n");
	    }
	    
	    $srtx_titulek_cislo = $srtx_radek;

	    chomp($srtx_radek = <ZDROJ_SRTX>);
	    if ( index($srtx_radek,'-->')<0 ) {
		close (ZDROJ_SRTX);
		close (NOVY_SRT);
		die ("Vstupni soubor nema format SRT titulku!!!\n");
	    }

	    $srtx_titulek_casovani = $srtx_radek;

	    chomp($srtx_radek = <ZDROJ_SRTX>);
	    if ( index($srtx_radek,'pgm')<0 ) {
		close (ZDROJ_SRTX);
		close (NOVY_SRT);
		die ("Vstupni soubor nema definovan zdroj PGM titulku!!!\n");
	    }
	
#def $pgm_soubor - obsahuje jmeno PGM souboru s titulky - postupne nacitano z .srtx

	    ( $pgm_soubor ) = $srtx_radek =~ /^(.*\.pgm)/;

	    &vlastnosti_obrazku;
#	    &vypis_vlastnosti_obrazku;
	    &zpracuj_titulek;

	    print NOVY_SRT "$srtx_titulek_cislo\n";
	    print NOVY_SRT "$srtx_titulek_casovani\n";
	    
	    @text_titulku = split(/\|/,$txt_radek);

	    foreach $txt_radek ( @text_titulku ) {
	    
		print NOVY_SRT "$txt_radek\n";
	    
	    }

	    print NOVY_SRT "\n";

	}

    }

    close(ZDROJ_SRTX);
    close(NOVY_SRT);

}
#-------------------------------------------------------------------------------


#===============================================================================
#vstup:  jmeno PGM souboru s titulky v $pgm_soubor
#vystup: napleni globalnich promennych $sirka,$vyska,$delka_hlavicky
sub vlastnosti_obrazku {
    my ( @hlavicka );

    open( PGM_ZDROJ, $pgm_soubor ) or die ("Nemohu otevrit soubor \'$pgm_soubor\'!\n");

    for ( $i=1 ; $i <= 3 ; $i++) {
	
	$hlavicka[$i] = <PGM_ZDROJ>;
    
    }

    close(PGM_ZDROJ);

#def: @hlavicka - pole s hlavickou PGM obrazku - na 3.radku je sirka a vyska
#def: $sirka - sirka obrazku s titulky v pixelech
#def: $vyska - vyska obrazku s titulky v pixelech

    $delka_hlavicky = length($hlavicka[1].$hlavicka[2].$hlavicka[3])+4;
    ( $sirka, $vyska ) = $hlavicka[3] =~ /(\d+)\s(\d+)/;

}
#-------------------------------------------------------------------------------


#===============================================================================
sub vypis_vlastnosti_obrazku {

    print "PGM soubor:$pgm_soubor, $sirka x $vyska hlavicka: $delka_hlavicky bajtu\n";

}
#-------------------------------------------------------------------------------


#===============================================================================
#vstup:  
#vystup: 
sub zpracuj_titulek {
    my ( $record );

#def $pixel_vyska - vyska jednoho txt radku titulku v pixelech
#def $pixel_radek_index - pozice zpracovavaneho pixel-radku v PGM titulku
#def @pixel_radek_ok - pole obsahujici retezce prevedenych pixel-radku na text


    open( PGM_ZDROJ, $pgm_soubor) or die ("Nemohu otevrit soubor \'$pgm_soubor\'!\n");

    print "Zpracovavam titulky \'$pgm_soubor\'\n";

# pro ladici ucely - do souboru NOVY se vypisuji pixel PGM prevedene na txt
# znaky a na konec se pripoji OCR databaze [rozpoznany znak;bit-vektory znaku]
#
#    open( NOVY, ">$pgm_soubor.new") or die ("Nemohu zalozit soubor \'$pgm_soubor.new\'!\n");

    read( PGM_ZDROJ, $record, $delka_hlavicky ); #posun v PGM souboru za hlavicku
    undef $record;

    $pixel_radek_index = 0;

    $txt_radek = "";

    do {
    
	@pixel_radek_ok = ();
	&nacti_cely_radek_titulku;

	&analyzuj_znaky_na_radku if $pixel_vyska>=$min_pixel_vyska;
#	print "$txt_radek\n";

	$txt_radek .= "|"; #oddelovac jednotlivych txt radku titulku v jednom PGM souboru

# tisk txt reprezentace PGM titulku pro jeden rozpozneny radek textu
#
#	if ( $pixel_vyska >= $min_pixel_vyska ) {
#	
#	    foreach $zaznam (@pixel_radek_ok) {
#    		print NOVY "$zaznam\n"; 
#	    }
#	    
#	    print NOVY "$txt_radek\n";
#	    print NOVY "\n";
#	    undef $zaznam;
#
#	}
	
    } while ( $pixel_radek_index < $vyska );
    
    close(PGM_ZDROJ);

#    close(NOVY);

}
#-------------------------------------------------------------------------------


#===============================================================================
#vstup:  musi byt otevren obrazek s titulkem jako PGM_ZDROJ a nactena hlavicka PGM
#vystup: vytvori pole retezcu, kde kazdy retezec je jeden prevedeny pixel-radek
#        z jednoho textoveho radku titulku v PGM obrazku
sub nacti_cely_radek_titulku {
    my ( $pixel_radek );
    
#def $pixel_radek - jeden pixel radek prevedeny na retezec/text

    $pixel_vyska = 0;

    do {
	
	$pixel_radek = &cti_pixel_radek_titulku;
	if ( (index($pixel_radek,BOD) >= 0) or ($pixel_vyska>0 and $pixel_vyska<$min_pixel_vyska) ) {
	    $pixel_radek_ok[$pixel_vyska]=$pixel_radek;
	    $pixel_vyska++;
	}
	$pixel_radek_index++;
#	print "pixel_radek_index:$pixel_radek_index\n";
    
    } until ( ((index($pixel_radek,BOD) < 0) and ($pixel_vyska>$min_pixel_vyska)) or $pixel_radek_index>=$vyska );

}
#-------------------------------------------------------------------------------


#===============================================================================
#vstup:  musi byt otevren obrazek s titulkem jako PGM_ZDROJ a nastavena spravna
#        pozice pro cteni ze souboru (za hlavickou PGM souboru)
#vystup: retezec obsahujici prevedeny pixel-radek jednoho textoveho radku titulku
sub cti_pixel_radek_titulku {
    my ( $record, $prevedeno );    
    
#def $record - obsahuje nacteny pixel-radek z obrazku titulku
#def $prevedeno - je do nej prevaden pixel-radek na text

	read( PGM_ZDROJ, $record, $sirka );
        $prevedeno = "";
	
        for ( $i = 0; $i < $sirka ; $i++ ) {
	
	if ( ord(substr($record,$i,1)) > 0  ) { $prevedeno.=" "; }
    	  else
	    { $prevedeno.=BOD; }

	}

    return $prevedeno;
}
#-------------------------------------------------------------------------------


#===============================================================================
#vstup:  potrebuje pole @pixel_radek_ok naplnene pixel radky titulku
#vystup: 
sub analyzuj_znaky_na_radku {


    &pixel_sloupce_radku_textu_na_bit_vektory;

    $ocr_sloupec = $left_pixel;

    while ( $ocr_sloupec < $right_pixel ) {

	$txt_radek .= &exact_match_ocr;
	
    }

}
#-------------------------------------------------------------------------------


#===============================================================================
#vstup:  potrebuje pole @pixel_radek_ok naplnene pixel-radky titulku
#vystup: naplni pole @pixel_sloupec_ok obsahujici bitove vektory pixel-sloupcu radku textu
sub pixel_sloupce_radku_textu_na_bit_vektory {
    my ( $p_s_sub, $p_r_sub );
    my ( $pixel_sloupec ) = "";

#def $p_s_sub - pixel-sloupec v radku txt titulku (pro pohyb v poli @pixel_radek_ok
#def $p_r_sub - pixel-radek v radku txt titulku (pro pohyb v poli @pixel_radek_ok
#def $left_pixel - prvni pixel textu v obrazku titulku (vlevo)
#def $right_pixel - posledni pixel textu v obrazku titulku (vpravo)
#def $pixel_sloupec - obsahuje bitovou reprezentaci pixel-slupce jednoho
#		      txt radku titulku; jde o bitovy vektor!!!
#def $pixel_sloupec_ok - pole tvorene bitovymi vektory $pixel_sloupec

    $left_pixel = $sirka;
    $right_pixel = 0;

    for ( $i=0; $i<=$pixel_vyska; $i++ ) {
    
	if ( (index($pixel_radek_ok[$i], BOD) < $left_pixel) and (index($pixel_radek_ok[$i], BOD) >= 0) ) {
	    $left_pixel = index($pixel_radek_ok[$i], BOD);
	}

	if ( rindex($pixel_radek_ok[$i], BOD) > $right_pixel ) {
	    $right_pixel = rindex($pixel_radek_ok[$i], BOD);
	}

    }

    for ( $p_s_sub = $left_pixel; $p_s_sub <= $right_pixel; $p_s_sub++ ) {

	for ( $p_r_sub=0; $p_r_sub < $pixel_vyska; $p_r_sub++ ) {
    
	    if ( substr($pixel_radek_ok[$p_r_sub], $p_s_sub, 1) eq BOD ) {
		vec($pixel_sloupec, $p_r_sub , 1) = 1;
	    }

	}
    
	$pixel_sloupec_ok[$p_s_sub] = $pixel_sloupec;

	$pixel_sloupec="";
    
    }

}
#-------------------------------------------------------------------------------


#===============================================================================
#vstup:  potrebuje pole @pixel_sloupec_ok obsahujici bitove vektory pixel-sloupcu
#vystup: vraci rozpoznany znak a vytvari hash jiz rozpoznanych znaku
sub exact_match_ocr {
    my ( $rozpoznano ) = "";
    my ( $pocet_prazdnych_sloupcu ) = 0;
    my ( $i );
    
    @sada_sloupcu_bit_vektoru = ();    

    if ( index(unpack("b*",$pixel_sloupec_ok[$ocr_sloupec]),"1") < 0 ) {
    
# ++++++++++++ rozliseni mezery mezi pismeny od mezery mezi slovy ++++++++++++
	
	do {
	
	    $pocet_prazdnych_sloupcu++;
	    $ocr_sloupec++;
	    
	} while ( index(unpack("b*",$pixel_sloupec_ok[$ocr_sloupec]),"1") < 0 );
	
	if ( $pocet_prazdnych_sloupcu >= $min_sirka_mezery ) {
	
	    $rozpoznano = " ";
	}
	    
    } else {
    
# ++++++++++++ rozpoznani znaku ++++++++++++++

	if ( $ocr_sloupec > $left_pixel ) {
    
	    $pravy_sl = $pixel_sloupec_ok[$ocr_sloupec];
	    $levy_sl = &uprav_pixel_sloupec($pixel_sloupec_ok[$ocr_sloupec-1], $pravy_sl);

# 	++++++++++ zde se vraci a hleda zacatek znaku ++++++++++

	    $posun_zpet = 1;

	    while ( (index(unpack("b*",$levy_sl),"1") >= 0) and ($ocr_sloupec-1 > $left_pixel) ) {
	
#		print unpack("b*",$pravy_sl),"\n";

		last if $posun_zpet > $max_prekryv;

		$ocr_sloupec--;
		$posun_zpet++;
		$pravy_sl = $levy_sl;
		$levy_sl = &uprav_pixel_sloupec($pixel_sloupec_ok[$ocr_sloupec-1], $pravy_sl, 1);

	    }

#	    print "\n\n"; #patri k print unpack vyse


	} else {
    
	    $pravy_sl = $pixel_sloupec_ok[$ocr_sloupec];
    
	}


	$levy_sl = $pravy_sl;
	$pravy_sl = &uprav_pixel_sloupec($pixel_sloupec_ok[$ocr_sloupec+1], $levy_sl);

# 	++++++++++ postupuje vpred a hleda konec znaku ++++++++++++++

	while ( index(unpack("b*",$pravy_sl),"1") >= 0 and $ocr_sloupec+1 < $right_pixel ) {

	    push(@sada_sloupcu_bit_vektoru, $levy_sl);
	    $ocr_sloupec++;
	    $levy_sl = $pravy_sl;
	    $pravy_sl = &uprav_pixel_sloupec($pixel_sloupec_ok[$ocr_sloupec+1], $levy_sl);
	
	}
    
	push(@sada_sloupcu_bit_vektoru, $levy_sl);

# 	+++++++++++ kontrola zda uz neni na poslednim znaku na radku +++++++++++

	if ( $ocr_sloupec+1 == $right_pixel ) {
    
	    if ( index(unpack("b*",$pravy_sl),"1") >= 0 ) {
	    
		push(@sada_sloupcu_bit_vektoru, $pravy_sl);
	    
	    }
	    $ocr_sloupec++;

	}

	$pixel_sirka_znaku = @sada_sloupcu_bit_vektoru;

	if ( $pixel_sirka_znaku > 2*$max_prekryv )  { 
	
	
#	    ++++++++ kvuli diakritice nad y,u,Y,U,N - doplneni stredni +++++++++
#	    ++++++++ casti rozpoznaneho znaku oproti uprave pixel sloupcu ++++++
	    for ( $i = $max_prekryv; $i < $pixel_sirka_znaku - $max_prekryv; $i++ ) {
		$sada_sloupcu_bit_vektoru[$i] = $pixel_sloupec_ok[$ocr_sloupec-$pixel_sirka_znaku+$i+1];
	    }

#	    ++++++++ znovu projde okraje znaku napr. kvuli kurzive S,Z,? aj. +++
#	    ++++++++ tady prochazi levy okraj znaku doleva +++++++++++++++++++++
	    for ( $i = $max_prekryv-1; $i >= 0; $i-- ) {
		$sada_sloupcu_bit_vektoru[$i] = &uprav_pixel_sloupec($pixel_sloupec_ok[$ocr_sloupec-$pixel_sirka_znaku+$i+1],$sada_sloupcu_bit_vektoru[$i+1]);
	    }

#	    ++++++++ tady prochazi pravy okraj doprava a jeste dale ++++++++++++
	    for ( $i = 0; $i < $max_prekryv; $i++ ) {
		pop(@sada_sloupcu_bit_vektoru); #odstrani pravy okraj znaku
	    }

	    $pixel_sirka_znaku = @sada_sloupcu_bit_vektoru;

	    $ocr_sloupec -= $max_prekryv-1;
	    $levy_sl = &uprav_pixel_sloupec($pixel_sloupec_ok[$ocr_sloupec],$sada_sloupcu_bit_vektoru[$pixel_sirka_znaku-1]);
	    $pravy_sl = &uprav_pixel_sloupec($pixel_sloupec_ok[$ocr_sloupec+1], $levy_sl);

#	    	++++++++++ postupuje vpred a hleda konec znaku +++++++++++++++++

	    while ( index(unpack("b*",$pravy_sl),"1") >= 0 and $ocr_sloupec+1 < $right_pixel ) {

		push(@sada_sloupcu_bit_vektoru, $levy_sl);
		$ocr_sloupec++;
		$levy_sl = $pravy_sl;
		$pravy_sl = &uprav_pixel_sloupec($pixel_sloupec_ok[$ocr_sloupec+1], $levy_sl);
	
	    }

	    push(@sada_sloupcu_bit_vektoru, $levy_sl);

# 		+++++++++++ kontrola zda uz neni na poslednim znaku na radku +++

	    if ( $ocr_sloupec+1 == $right_pixel ) {
    
		if ( index(unpack("b*",$pravy_sl),"1") >= 0 ) {
	    
		    push(@sada_sloupcu_bit_vektoru, $pravy_sl);
	    
		}
		$ocr_sloupec++;

	    }

	    $pixel_sirka_znaku = @sada_sloupcu_bit_vektoru;


#	    for ( $i = $pixel_sirka_znaku - $max_prekryv; $i < $pixel_sirka_znaku ; $i++ ) {
#		$sada_sloupcu_bit_vektoru[$i] = &uprav_pixel_sloupec($pixel_sloupec_ok[$ocr_sloupec-$pixel_sirka_znaku+$i+1],$sada_sloupcu_bit_vektoru[$i-1]);
#	    }

	}

    }

#    if ( $pocet_prazdnych_sloupcu == 0 ) {
    $pixel_sirka_znaku = @sada_sloupcu_bit_vektoru;

    if ( $pocet_prazdnych_sloupcu == 0 and $pixel_sirka_znaku > 1 ) {
    
#def $pixel_sirka_znaku - sirka rozpoznaneho znaku v pixelech; odpovida poctu
#                         bit-vektoru v poli @sada_sloupcu_bit_vektoru

	#porovnani znaku s databazi a pripadny dodaz na novy znak

	&posun_bit_vektoru_doleva; # vsechny znaky zarovna doleva, aby byly stejne

#	print "Vyhledavam v OCR databazi:";

	$ocr_key = 0; #vygenerovani klice pro hash %ocr_databaze
	foreach $vektor ( @sada_sloupcu_bit_vektoru ) {
	    $ocr_key += &ocr_key_vzorec($vektor);
	}

	if ( exists($ocr_databaze{$ocr_key}) ) {

	    foreach $vzorek ( @{$ocr_databaze{$ocr_key}} ) {
    

#	    	print "Prochazim OCR databazi,  znak:${$vzorek}[0]\n";
#	    	print ">";

#	    	@sada_bit_vektoru_ocr_databaze = ();
		@sada_bit_vektoru_ocr_databaze = @$vzorek;

		if ( $pixel_sirka_znaku == @sada_bit_vektoru_ocr_databaze-1 ) {

		    $shoda = 1;

		    for ( $i = 0; $i < $pixel_sirka_znaku; $i++ ) {

#			print "porovnavam bit-vektor$i\n";

			if ( $sada_bit_vektoru_ocr_databaze[$i+1] ne $sada_sloupcu_bit_vektoru[$i] ) {
			    $shoda = 0;
#		    	    print "Porovnani vuci znaku ${$vzorek}[0] NEVYHOVELO !!!\n";
			}

#			print "shoda:$shoda\n";

			last unless $shoda;

		    }
		
		} else { $shoda = 0; }

		if ( $shoda ) {

		    $rozpoznano = ${$vzorek}[0];
#		    print "ZNAK $rozpoznano ROZPOZNAN !!!\n";

		}

		last if $shoda;

	    }

	}

	if ( $rozpoznano eq "" ) {

	    &tisk_casti_titulku;
	    print "Analyzuji soubor:\'$pgm_soubor\'\n";
	    print "Vloz odpovidajici znak a stiskni [ENTER]:";
	    chomp($rozpoznano = <STDIN>);
	    if ( $rozpoznano eq "I" ) {
		print "POZOR! Obvykle male L a velke I vypadaji stejne. V takovem pripade doporucuji zadat male L\n";
		print "Vloz odpovidajici znak a stiskni [ENTER]:";
		chomp($rozpoznano = <STDIN>);
	    }

	    if ( $rozpoznano ne "" ) {

		unshift(@sada_sloupcu_bit_vektoru,$rozpoznano);
		push(@{$ocr_databaze{$ocr_key}},[@sada_sloupcu_bit_vektoru]);

	    }

	    print "Zpracovavam titulky \'$pgm_soubor\'\n";

	}

    }

    $ocr_sloupec++; #inkrementuje se az tady kvuli tisku sady vektoru znaku
		     #a radeji vice, abychom se vyhnuli zacykleni

    return $rozpoznano;

}
#-------------------------------------------------------------------------------


#===============================================================================
#vstup:  pole @sada_sloupcu_bit_vektoru musi byt naplneno rozpoznanym znakem
#vystup: stejne pole, ale bit vektory jsou zarovnany vlevo podle nejnizsiho bitu
sub posun_bit_vektoru_doleva {
    my ( $posun_bitu_vlevo ) = 255; #jen inicializace, nejaka max.hodnota
    my ( $prvni_vlevo, $posledni_bit_vektoru );
    my ( $i );

    foreach $vektor ( @sada_sloupcu_bit_vektoru ) {

	$prvni_vlevo =  index(unpack("b*",$vektor),"1");
	if ( $prvni_vlevo >= 0 and $prvni_vlevo < $posun_bitu_vlevo ) { $posun_bitu_vlevo = $prvni_vlevo; }

	last if $posun_bitu_vlevo == 0;

    }

    if ( $posun_bitu_vlevo > $pixel_vyska/2 ) { $posun_bitu_vlevo--; }
#   aby nedoslo k zamene carky za slovy a hacku u d/t,zustane po posunu vlevo jeden prazdny bit

    $posledni_bit_znaku = 0;
#def $posledni_bit_znaku - globalni promenna vyuzita pri tisku sady bit-vektoru znaku

    for ( $i=0; $i < $pixel_sirka_znaku; $i++) {
	
	$posledni_bit_vektoru = rindex(unpack("b*",$sada_sloupcu_bit_vektoru[$i]),"1");
	$sada_sloupcu_bit_vektoru[$i] = pack("b*",substr(unpack("b*",$sada_sloupcu_bit_vektoru[$i]),$posun_bitu_vlevo,$posledni_bit_vektoru-$posun_bitu_vlevo+1));
	if ( ($posledni_bit_vektoru-$posun_bitu_vlevo) > $posledni_bit_znaku ) {
	    $posledni_bit_znaku = $posledni_bit_vektoru-$posun_bitu_vlevo;
	}
	
    }

}
#-------------------------------------------------------------------------------


#===============================================================================
#vstup:  bit-vektor libovolne delky
#vystup: cislo, ktere je souctem ciselnych reprezentaci jednotlivych bajtu v bit-vektoru
sub ocr_key_vzorec {
    my ( $vektor ) = @_;
    my ( @bajty ) = ();
    my ( $bajt, $celkem ) = 0;

    ( @bajty ) = unpack("C*",$vektor);
    foreach $bajt ( @bajty ) { $celkem += $bajt; }

    return $celkem;

}
#-------------------------------------------------------------------------------


#===============================================================================
#vstup:  
#vystup: 
sub tisk_casti_titulku {
    my ( $segment, $start1, $start2, $kolik1, $kolik2 );
    my ( $i );

    print "\n"; #horizontalni oddeleni tisknute casti titulku od ostatniho textu

#    print "OCR_key:$ocr_key\n\n";

#    print "pixel_radek_index:$pixel_radek_index,pixel_vyska:$pixel_vyska,";
#    print "ocr_sloupec:$ocr_sloupec,pixel_sirka_znaku:$pixel_sirka_znaku\n";

# tisk sady bit vektoru jako 1 a 0
#
#    foreach $vektor ( @sada_sloupcu_bit_vektoru ) {
#	print unpack("b*", $vektor),"\n";
#    }


# tisk casti titulku prevedeneho do txt odpovidajici sade bit vektoru
#

    $start1 = $ocr_sloupec - $pixel_sirka_znaku - int(($sirka_radku_terminalu-$pixel_sirka_znaku)/2) + 1;
    if ( $start1 < $left_pixel ) { $start1 = $left_pixel; }
    $kolik1 = $ocr_sloupec - $pixel_sirka_znaku - $start1 +1;
    
    $start2 = $ocr_sloupec + 1;
    $kolik2 = $right_pixel - $ocr_sloupec;
    if ( $kolik2 > int(($sirka_radku_terminalu-$pixel_sirka_znaku)/2) ) {
	$kolik2 = int(($sirka_radku_terminalu-$pixel_sirka_znaku)/2); 
    }

#    print "pixel sirka znaku:$pixel_sirka_znaku, start1:$start1, start2:$start2, kolik1:$kolik1, kolik2:$kolik2\n";

    for ( $i = 0; $i < $pixel_vyska; $i++ ) {

	#tisk okoli pred rozpoznanym znakem
	if ( $kolik1 > 0 ) {
	    $segment = substr($pixel_radek_ok[$i],$start1,$kolik1);
	    $segment =~ s/#/\./g;
	    print $segment;
	}

#	print "\'".substr($pixel_radek_ok[$i], $ocr_sloupec-$pixel_sirka_znaku+1, $pixel_sirka_znaku)."\'\n";
	print substr($pixel_radek_ok[$i], $ocr_sloupec-$pixel_sirka_znaku+1, $pixel_sirka_znaku);

	#tisk okoli za rozpoznanym znakem
	if ( $kolik2 > 0 ) {
	    $segment = substr($pixel_radek_ok[$i],$start2,$kolik2);
	    $segment =~ s/#/\./g;
	    print $segment;
	}

	print "\n"; #ukonceni jednoho radku tisknute casti titulku

    }

    print "\n"; #horizontalni oddeleni tisknute casti titulku od ostatniho textu

    if ( $opt_r ) {

	&tisk_sady_vektoru;
	print "\n";

    }

}
#-------------------------------------------------------------------------------


#===============================================================================
sub tisk_sady_vektoru {
    my ( $max_delka ) = 0;
    my ( $vektor, $i, $j );
    
    for ( $i = 0; $i <= $posledni_bit_znaku; $i++ ) {

	for ( $j = 0; $j < @sada_sloupcu_bit_vektoru; $j++ ) {
    
	    if ( vec($sada_sloupcu_bit_vektoru[$j],$i,1) ) {
		print BOD; }  else { print " "; 
	    }
    
	}

	print "\n";
        
    }

}
#-------------------------------------------------------------------------------


#===============================================================================
#vstup:  
#vystup: 
sub uprav_pixel_sloupec {
    my ( $meneny_sl, $vzorovy_sl, $zpatecka ) = @_;
    my ( $prvi_nastaveny, $posledni_nastaveny ) = 255; #inicializace na nejakou max hodnotu
    my ( $zachovat ) = 0;
    my ( $i, $index );

#    print "v:",unpack("b*",$vzorovy_sl)," m:",unpack("b*",$meneny_sl)," zm:";

    $index = length($meneny_sl)*8 - 1;

    while ( $index >= 0 ) {
    
	#prochazi pixel sloupce zdola nahoru - kvuli smeru sklonu diakritiky

	if ( vec($meneny_sl, $index, 1) ) {

	    $prvni_nastaveny = $index;

	    while ( vec($meneny_sl, $index, 1) ) {
		$index--;
	    }
	    $posledni_nastaveny = $index+1;

	    $zachovat = 0;
	    for ( $i = $prvni_nastaveny; $i>=$posledni_nastaveny; $i-- ) {

		if ( vec($vzorovy_sl, $i, 1) ) { $zachovat = 1; }
		last if $zachovat;

	    }

	    if ( $zachovat==0 and $zpatecka==0 ) {
		    # pro zachovani diakritiky nad znaky
		    # nepostihne diakritiku nad u,y,U,Y,N

		for ( $i = $prvni_nastaveny+1 + $max_pixel_vzdalenost_diakr; $i > $prvni_nastaveny; $i-- ) {

#		    next if $i>(length($meneny_sl)-1);
		    if ( vec($meneny_sl, $i, 1) ) { $zachovat = 1; }
		    last if $zachovat;

		}
		    
		if ( $zachovat == 0 and (index(unpack("b*",$vzorovy_sl),"1") == rindex(unpack("b*",$vzorovy_sl),"1")) and $posledni_nastaveny<$pixel_vyska/2 ) {
			# vyjimecne u dlouheho i se stava, ze carka zacina pred i, a pak
			# by chybela cast pod carkou nad i
			# aby ale nedochazelo k zacykleni pri kurzive, je nutno pridat dalsi
			# test, kdy predchozi pixel-sloupec obsahuje jen jeden aktivni pixel

		    for ( $i = $posledni_nastaveny-1 - $max_pixel_vzdalenost_diakr; $i < $posledni_nastaveny; $i++ ) {

#			next if $i < 0;
			if ( vec($meneny_sl, $i, 1) ) { $zachovat = 1; } #puvodne $meneny_sl
			last if $zachovat;

		    }

		}

	    }

	    unless ( $zachovat ) {

		for ( $i = $prvni_nastaveny; $i >= $posledni_nastaveny; $i-- ) {

		    vec($meneny_sl, $i, 1) = 0;

		}

	    }

	}

	$index--;

    }

#    print "modifikuju bit vektor sloupce\n";

#    print unpack("b*",$meneny_sl),"\n";

    return $meneny_sl;

}
#-------------------------------------------------------------------------------


#===============================================================================
#vstup:  nic
#vystup: nic resp. tisk napovedy na obrazovku
sub napoveda {

    print "\n";
    print "Program pgm2srt slouzi ke zpracovani DVD titulku prevedenych na jednotlive PGM\n";
    print "obrazky pomoci transcode, resp. jeho soucasti tcextract a subtitle2pgm.\n";
    print "PGM obrazy jednotl. titulku musi byt vyhradne cernobile bez odstinu sede a dale \n";
    print "je vyzadovan soubor .srtx, ktery generuje program subtitle2pgm.\n";
    print "Pouziti: pgm2srt [volby] SRTX_soubor\n";
    print "Pozor!!! nazev vstupniho SRTX souboru musi byt uplne posledni!\n";
    print "  -h          tento help\n";
    print "  -v          verze tohoto programu\n";
    print "  -o <nazev>  output - mozno zadat nazev noveho souboru SRT titulku\n";
    print "                     - bez pouziti volby je vytvoren soubor *.new\n";
    print "  -s <nazev>  save - ulozi vytvorenou databazi znaku jako <nazev>.pgm2srt\n";
    print "  -l <nazev>  load - pouzije drive vytvorenou databazi rozpoznanych znaku\n";
    print "  -c <cislo>  character - moznost zmenit implicitni nastaveni minimalni vysky\n";
    print "                          znaku v pixelech (pouzito z duvodu diakritiky)\n";
    print "  -d <cislo>  distance - zmeni implicitni maximalni vertikalni pixel-vzdalenost\n";
    print "                         diakritiky a tecek od znaku\n";
    print "  -g <cislo>  gap - zmeni implicitni minimalni horizontalni pixel-vzdalenost\n";
    print "                    stanovujici mezeru mezi slovy (pozor na kurzivu!)\n";
    print "  -e <cislo>  over - zmeni implicitni maximalni prekryv znaku v pixelech\n";
    print "                   - uplatni se pri kurzive, kdy vrchni cast predchazejiciho\n";
    print "                     znaku zasahuje nad dolni cast znaku nasledujiciho\n";
    print "  -w <cislo>  width - zmeni implicitni nastaveni sirky terminalu, tj. poctu\n";
    print "                      znaku na radek pri vypisu casti rozpoznavaneho titulku\n";
    print "  -r          recognize - vypisuje navic pod cast titulku presnou podobu\n";
    print "                          rozpoznaneho znaku\n";
    print "  -q          quiet - TO DO\n";
    print "                    - zabrani vypisu do terminalu - ulatni se v GUI\n";
    print "\n";

}
#-------------------------------------------------------------------------------


#===============================================================================
#vstup:  nic
#vystup: nic resp. tisk verze na obrazovku
sub verze {

    print "pgm2srt ver. ",VERZE,"\n";
    print "Vytvoreno na platforme LinuxMandrake 9.0; perl v5.8.0\n";
    print 'Tomas Hanusek, xhant04@centrum.cz, http://hanus.host.sk',"\n";

}
#-------------------------------------------------------------------------------


#===============================================================================
sub uloz_ocr_databazi {
    my ( @sada_bit_vektoru, $prvku_pole, $vzorek );

    open (OCR, ">$opt_s.pgm2srt") or die ("Nemohu zalozit soubor \'$opt_s.pgm2srt\'\n");
    
    print "Ukladam OCR databazi...\n";

    print OCR "# Datovy soubor programu pgm2srt ver.",VERZE,".\n";
    print OCR "# Obsahuje rozpoznane znaky prislusnych PGM titulku.\n";
    print OCR "# Format souboru:\n";
    print OCR "# % -takto se znaci klice hashe %ocr_databaze - ty jsou vypocitany z podoby\n";
    print OCR "#    rozpoznaneho znaku jako soucet jednotlivych bajtu ziskanych prevedenim\n";
    print OCR "#    jednotl. bit-vektoru znaku po osmi bitech na cisla 0-255.\n";
    print OCR "# > -oznaceni ukazatele na pole, obsahujici bit-vektory znaku; jelikoz zpusob\n";
    print OCR "#    stanoveni hashoveho klice nezarucuje jednoznacnost pro vsechny znaky, muze\n";
    print OCR "#    mit stejny hashovy klic vice znaku - proto se ukladaji do poli.\n";
    print OCR "#   -jde tedy o pole poli, pricemz prvky tohoto pole jsou odkazy na dalsi pole\n";
    print OCR "# A -oznacuje jiz konkterni pole, ktere obsahuje bit-vektorovou reprezentaci\n";
    print OCR "#   znaku A. Prvni polozkou pole je znak A, ostatni polozky jsou bit vektory, ktere\n";
    print OCR '#   jsou zde ulozeny reprezentaci jednicek a nul pomoci unpack("b*",$bit-vektor)',"\n";
    print OCR "#\n";

    foreach $ocr_key ( keys(%ocr_databaze) ) {
    
	print OCR "%","$ocr_key\n";

	foreach $vzorek ( @{$ocr_databaze{$ocr_key}} ) {
	
	    @sada_bit_vektoru = @$vzorek;
	    $prvku_pole = @sada_bit_vektoru;
	    print OCR ">","$sada_bit_vektoru[0]\n";
	    for ( $i = 1; $i < $prvku_pole; $i++ ) {
		print OCR unpack("b*",$sada_bit_vektoru[$i]),"\n";
	    }
	
	}
    
    }

    close(OCR);

}
#-------------------------------------------------------------------------------


#===============================================================================
sub nacti_ocr_databazi {
    my ( @sada_bit_vektoru, $radek, $znak );

    unless ( open (OCR, "$opt_l") ) {
    
	open (OCR, "$opt_l.pgm2srt") or die ("Nemohu otevrit soubor s  OCR databazi\n");
    
    }
    
    print "Nacitam OCR databazi...\n";

    while ( chomp($radek = <OCR>) ) {

	while ( index($radek,"%") == 0 ) {
	
	    ($ocr_key) = substr($radek,1);
	    chomp($radek = <OCR>);

	    while ( index($radek,">") == 0 ) {

		($znak) = substr($radek,1);
		if ( $znak eq "" ) {
		    close(OCR);
		    die "Chybny format OCR databaze!!!\n";
		}
		
		@sada_bit_vektoru = ();
		$sada_bit_vektoru[0] = $znak;
		chomp($radek = <OCR>);

#		print "%",$ocr_key,"\n>",$znak,"\n";

		while ( $radek ne "" and index($radek,"#")<0 and index($radek,"%")<0 and index($radek,">")<0 ) {

		    push(@sada_bit_vektoru,pack("b*",$radek));
		    chomp($radek = <OCR>);

		}

		push(@{$ocr_databaze{$ocr_key}},[@sada_bit_vektoru]);

	    }

	}

    }

    close (OCR);

}

