Beefy Boxes and Bandwidth Generously Provided by pair Networks
Perl: the Markov chain saw


by QuillMeantTen (Friar)
on Dec 03, 2015 at 09:20 UTC ( #1149273=CUFP: print w/replies, xml ) Need Help??

Greetings fellow monks,

Yesterday my lady asked me if I could do her a favor, gallant fool that I am I answered at once

"Of course, my paramour, it would be my honor to take on any quest, to slay any foe metaphorical or otherwise for your honor". For my defense the day before I forgot to make her lasagnas as promised and she was quite disappointed with my chicken and mushroom pie so that's why I did not ask what the task would be before accepting.

A strange activity was asked of me : writing raffle tickets with nice images in such a way that they could be easily printed and then cut out as individual tickets.
As more than 3 hundreds of them were required by 6 pm the same day (someone had dumped the task on her without warning) she told me that using Excel was a solution but as it was computer related she hoped I knew some wizardry to accomplish the task in mere moments.

So I grabbed my spear, shield, poleaxe, steed and my trusted GCC (gnu compiler cat, an universal syntax checker that will sit on my lap while I code and try to rip my throat if I move and sometimes when I make syntax mistakes)

I soon came up with this idea : Write it using latex, break the latex doc in discrete parts and then use a perl script to rearrange them as needed

Here is the resulting script : you give it a path to the image you want, the number of tickets you want and the scale for the image and you should (hopefully) get some kind of result.
Also you will need pdflatex.
As usual, I'm looking for ways to get better so constructive criticism is welcome.

Update: added autodie, thanks athanasius
use constant, rewrite the first loop, thanks anonymous monk, I'm going to read on the use of the DATA section

Aaaand another update, it's been a long time but I had to modify my script so it could do better:
Now you can pass more arguments: number of tickets in each column and output filename

#!/usr/bin/perl -w use strict; use autodie; use warnings; use Carp qw(croak); use Getopt::Std; sub main{ my ($image,$number,$scale,$COLS) = @_; my $header = '\documentclass[12pt]{report} \usepackage{graphicx} \usepackage{array} \usepackage{makecell} \usepackage[T1]{fontenc} \usepackage[margin=0.25in]{geometry} \usepackage[utf8]{inputenc} \begin{document} '; my $footer = '\end{document}'; open my $tombolatex, '>','int.tex'; print $tombolatex $header; my $body = '\begin{tabular}{'.('|c|' x $COLS).'} \hline'. (('\thead{Ticket} &'."\n") x ($COLS-1)). '\thead{Ticket}'."\n".'\\\\[6ex] \hline'. (('\makecell{\includegraphics[scale=ISCALE]{image}\\\\ Ticket} &'."\n" +)x ($COLS-1)). '\makecell{\includegraphics[scale=ISCALE]{image}\\\\ Ticket} \\\\[12ex +] \hline \end{tabular} '; print $tombolatex $body x (1 + $number / $COLS); print $tombolatex $footer; close $tombolatex; open $tombolatex, '>','res.tex'; open my $input,'<','int.tex'; my $tn = 1; my $iter = 0; my $find = 'Ticket'; $find = quotemeta $find; while(<$input>){ my $replace = "Ticket $tn"; my $line= $_; $line=~s/image/$image/g; $line =~s/ISCALE/$scale/g; if($line =~ s/$find/$replace/g){ if($tn % $COLS == 0){ if($iter == 1){ $tn++; $iter = 0; } else{ $tn -= ($COLS-1); $iter++; } } else{ $tn++; } } print $tombolatex $line; } } our ($opt_i,#image switch $opt_n,#number of tickets $opt_s,#image_scale $opt_c,#number of columns $opt_o);#output filename getopts('i:n:s:c:o:'); my @shortargs= ($opt_i,$opt_n,$opt_s,$opt_c,$opt_o); if(!defined($shortargs[0])|| !defined $shortargs[1] || !defined $shortargs[2]|| !defined $shortargs[3]||!defined $shortargs[4]){ croak <<"END" -i image to put on tickets: $shortargs[0] -n number of tickets: $shortargs[1] -s image scale: $shortargs[2] -c number of columns: $shortargs[3] -o filename: $shortargs[4] END } main @shortargs; `pdflatex res.tex`; unlink 'int.tex'; rename 'res.pdf', $shortargs[4]; my @res = glob "res.*"; unlink @res;

Replies are listed 'Best First'.
Re: raffle_tickets_generator
by Athanasius (Archbishop) on Dec 03, 2015 at 10:06 UTC

    Hello QuillMeantTen,

    As usual, I'm looking for ways to get better so constructive criticism is welcome.

    I can’t try out your code, as I don’t currently have pdflatex installed. But I notice that you call open and close without testing for failure. It’s good practice to either test each call explicitly:

    open(my $tombolatex, '>', 'int.tex') or die "Cannot open file 'int.tex' for writing: $!";

    or to put:

    use autodie;

    at the head of your script. See autodie.

    Hope that helps,

    Athanasius <°(((><contra mundum Iustus alius egestas vitae, eros Piratica,

      Yikes, I missed that, thank you. I already automatically add

      use strict; use warnings;
      but autodie does not come as easily to mind yet.

Re: raffle_tickets_generator
by Anonymous Monk on Dec 03, 2015 at 11:19 UTC

    Criticism invited, so here goes.

    • I'd write the long text strings as here-docs, or better yet, put them in __DATA__ section at the end.
      Paragraph mode perhaps to cut it up.
      my ($header, $body, $footer) = do { local $/ = ""; <DATA> };
    • I fail to see the reason to put $find through quotemeta. (And there's also the \Q\E).
    • It is advisable to use named constants instead of magic numbers: use constant COLS => 7;
    • For loop more concisely written using repetition operator: print $tombolatex $body x (1 + $N / COLS);
    • ...
    • All in all, it looks like a simple templating job.

      It is the first time I hear about the DATA section, thanks for pointing this feature out! also that way to write loops is great, I'm going to correct that at once.

        Good reference that talks about paragraph mode.

        use strict; use warnings; my ($first,$second,$third); { local $/ = ''; ($first, $second, $third) = <DATA>; } printf "First: %s", $first; printf "Second: %s", $second; printf "Third: %s", $third; __DATA__ this will go into the variable called first second here tail end charlie
        Dum Spiro Spero
Re: raffle_tickets_generator
by karlgoethebier (Abbot) on Dec 12, 2015 at 13:43 UTC

      Thank you for that input
      I did not know about the Template module, its very interesting and I shall be using it from now on.

        See also good old Text::Template by Dominus.

        Regards, Karl

        «The Crux of the Biscuit is the Apostrophe»

Re: raffle_tickets_generator
by FreeBeerReekingMonk (Deacon) on Dec 03, 2015 at 23:05 UTC

    Getting it to work is an art I have not mastered yet. It runs, but hangs, because pdflatex expects a prompt

    ! LaTeX Error: File `makecell.sty' not found. Type X to quit or <RETURN> to proceed, or enter new name. (Default extension: sty) Enter file name:

    I require package texlive-latex-extra which is a little too steep for my machine: 885MB for some fonts, and LaTeX utils. Ill have to think about it... nice storytelling prosa.

      Is there any way to redirect the pdflatex's IO so one could interact with it from the console used to launch the script?

Log In?

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: CUFP [id://1149273]
Front-paged by Corion
and the web crawler heard nothing...

How do I use this? | Other CB clients
Other Users?
Others chanting in the Monastery: (1)
As of 2023-06-02 04:16 GMT
Find Nodes?
    Voting Booth?

    No recent polls found