001 #!/usr/local/bin/perl -w 002 use strict; 003 use local::lib; 004 use POE; 005 use POE::Wheel::Run; 006 use Curses::UI::POE; 007 use Sysadm::Install qw(:all); 008 use File::Temp qw(tempfile); 009 use File::Basename; 010 011 my $PDF_DIR = "/tmp/artscan"; 012 mkd $PDF_DIR unless -d $PDF_DIR; 013 014 my $pidfile = "$PDF_DIR/pid"; 015 blurt "$$\n", $pidfile; 016 017 my @LBOX_LINES = (); 018 my $BUSY = 0; 019 my $LAST_PDF; 020 my @IMAGES = (); 021 my $HEAP; 022 023 my $CUI = Curses::UI::POE->new( 024 -color_support => 1, 025 inline_states => { 026 _start => sub { 027 $HEAP = $_[HEAP]; 028 $_[KERNEL]->sig( "USR1", 029 "article_scan" ); 030 }, 031 scan_finished => \&scan_finished, 032 article_scan => \&article_scan, 033 }); 034 035 my $WIN = $CUI->add("win_id", "Window"); 036 037 my $TOP = $WIN->add( qw( top Label 038 -y 0 -width -1 -paddingspaces 1 039 -fg white -bg blue 040 ), -text => "artscan v1.0" ); 041 042 my $LBOX = $WIN->add(qw( lb Listbox 043 -padtop 1 -padbottom 1 -border 1), 044 ); 045 046 my $FOOT = $WIN->add(qw( bottom Label 047 -y -1 -paddingspaces 1 048 -fg white -bg blue)); 049 050 footer_update(); 051 052 $CUI->set_binding(sub { exit 0; }, "q"); 053 $CUI->set_binding( \&article_new, "n"); 054 $CUI->set_binding( \&article_scan, "s" ); 055 $CUI->set_binding( \&article_finish, "f" ); 056 057 $CUI->mainloop; 058 059 ########################################### 060 sub article_new { 061 ########################################### 062 return if $BUSY; 063 @IMAGES = (); 064 footer_update(); 065 } 066 067 ########################################### 068 sub article_finish { 069 ########################################### 070 return if $BUSY; 071 $BUSY = 1; 072 073 $FOOT->text("Converting ..."); 074 $FOOT->draw(); 075 076 my @jpg_files = (); 077 078 for my $image ( @IMAGES ) { 079 my $jpg_file = 080 "$PDF_DIR/" . basename( $image ); 081 $jpg_file =~ s/\.pnm$/.jpg/; 082 push @jpg_files, $jpg_file; 083 task("convert", $image, $jpg_file); 084 } 085 086 my $pdf_file = next_pdf_file(); 087 088 $FOOT->text("Writing PDF ..."); 089 $FOOT->draw(); 090 091 task("convert", @jpg_files, $pdf_file); 092 unlink @jpg_files; 093 094 $LAST_PDF = $pdf_file; 095 @IMAGES = (); 096 097 lbox_add("PDF $LAST_PDF ready."); 098 footer_update(); 099 $BUSY = 0; 100 } 101 102 ########################################### 103 sub next_pdf_file { 104 ########################################### 105 my $idx = 0; 106 107 my @pdf_files = sort <$PDF_DIR/*.pdf>; 108 109 if( scalar @pdf_files > 0 ) { 110 ($idx) = ($pdf_files[-1] =~ /(\d+)/); 111 } 112 113 return "$PDF_DIR/" . 114 sprintf("%04d", $idx + 1) . ".pdf"; 115 } 116 117 ########################################### 118 sub task { 119 ########################################### 120 my($command, @args) = @_; 121 122 lbox_add("Running $command" . " @args"); 123 tap($command, @args); 124 } 125 126 ########################################### 127 sub article_scan { 128 ########################################### 129 return if $BUSY; 130 $BUSY = 1; 131 132 my($fh, $tempfile) = tempfile( 133 DIR => $PDF_DIR, 134 SUFFIX => ".pnm", UNLINK => 1); 135 136 lbox_add("Scanning $tempfile"); 137 138 my $wheel = 139 POE::Wheel::Run->new( 140 Program => "./scan.sh", 141 ProgramArgs => [$tempfile], 142 StderrEvent => 'ignore', 143 CloseEvent => "scan_finished", 144 ); 145 146 $HEAP->{scanner} = { 147 wheel => $wheel, file => $tempfile }; 148 149 $FOOT->text("Scanning ... "); 150 $FOOT->draw(); 151 } 152 153 ########################################### 154 sub scan_finished { 155 ########################################### 156 my($heap) = @_[HEAP, KERNEL]; 157 158 push @IMAGES, $heap->{scanner}->{file}; 159 delete $heap->{scanner}; 160 footer_update(); 161 $BUSY = 0; 162 } 163 164 ########################################### 165 sub footer_update { 166 ########################################### 167 my $text = "[n]ew [s]can [f]inish [q]" . 168 "uit (" . scalar @IMAGES . " pending)"; 169 170 if( defined $LAST_PDF ) { 171 $text .= " [$LAST_PDF]"; 172 } 173 $FOOT->text($text); 174 $FOOT->draw(); 175 } 176 177 ########################################### 178 sub lbox_add { 179 ########################################### 180 my($line) = @_; 181 182 if( scalar @LBOX_LINES >= 183 $LBOX->height() - 4) { 184 shift @LBOX_LINES; 185 } 186 push @LBOX_LINES, $line; 187 188 $LBOX->{-values} = [@LBOX_LINES]; 189 $LBOX->{-labels} = { map { $_ => $_ } 190 @LBOX_LINES }; 191 $LBOX->draw(); 192 }