Archive

Posts Tagged ‘cairo’

Sticker Generator

February 19th, 2011 3 comments

At KAM MFF CUNI, we have about ~60 to ~70 computers scattered over the department, be them at desks of professors, older ones stocked in the basements or near-identical rack servers. Especially when older machines are shuffled around, it is difficult to track them, and the standard tiny inventory stickers keep falling off (and you have to keep looking up the number).

Therefore, we are making stickers to put on all our computers with some details about them. I used that as a pretense for learning some basic Cairo and I really like the paradigm (though I wish text manipulation was be easier). In case anyone would find this ever useful (or just a good scaffolding for their own Cairo Perl script), the script goes here; the default sticker size is to have height of a 5.25″ drive bay and width so that two rows fit nicely on A4.

#!/usr/bin/perl
# (c) Petr Baudis  2011  MIT licence
# 
# Generate PDF with stickers.
# Expects tab-delimited columns on stdin:
# hostname mac invnumber buydate
 
use strict;
use warnings;
 
 
# -- User configuration --
 
our @paper = (598, 842); # A4, 72dpi
our @margin = (72, 72);
our @sticker = (227, 116);
our $filename = 'nalepky.pdf';
 
our $fontface = 'Arial';
our $ffontface = 'Courier New';
# large, normal, small
our @fontsize = (26, 15, 10);
our @linespacing = (18, 4, 18);
our $topmargin = 2;
 
our $contact = '<contact information>';
 
# -- User configuration end --
 
 
use lib 'perl';
use List::Util qw(min);
use List::MoreUtils qw(pairwise);
use Cairo;
 
our $surface = Cairo::PdfSurface->create ($filename, @paper);
 
# Effective surface area
our @surfsize = pairwise { $a - $b * 2 } @paper, @margin;
# Grid layout on effective surface
our @grid = pairwise { int($a / $b) } @surfsize, @sticker;
# Grid surface area
 
our @gridsurfsize = pairwise { $a * $b } @grid, @sticker;
# Start of grid surface so that it is centered on the paper
our @gridsurfstart = pairwise { ($a - $b) / 2 } @paper, @gridsurfsize;
 
# Produce a context for single sticker, starting at coordinates [0,0]
sub nalepka_cr {
        my ($surface, $cell) = @_;
        my @startM = pairwise { $a * $b } @sticker, @$cell;
        my @start = pairwise { $a + $b } @gridsurfstart, @startM;
 
        my $cr = Cairo::Context->create($surface);
        $cr->translate(@start);
 
        $cr->set_source_rgb(0, 0, 0);
        $cr->set_line_width(1);
        $cr;
}
 
# Centered text with top border at $$y. $size is index in font config above.
sub nalepka_text {
        my ($cr, $y, $face, $slant, $weight, $size, $text) = @_;
        $$y += $linespacing[$size] / 2;
 
        $cr->select_font_face($face, $slant, $weight);
        $cr->set_font_size($fontsize[$size]);
        my $textents = $cr->text_extents($text);
        my $fextents = $cr->font_extents();
        $$y += $fextents->{height};
        $cr->move_to(($sticker[0] - $textents->{width}) / 2, $$y);
        $cr->show_text($text);
 
        $$y += $linespacing[$size] / 2;
}
 
sub nalepka {
        my ($cr, $host, $mac, $inv, $since) = @_;
 
        $cr->rectangle(0, 0, @sticker);
        $cr->stroke;
 
        my $invs = $since ? "$inv      $since" : $inv;
 
 
        my $ypos = $topmargin - $linespacing[0] / 2;
        nalepka_text($cr, \$ypos, $fontface, 'normal', 'bold', 0, $host);
        nalepka_text($cr, \$ypos, $ffontface, 'normal', 'normal', 1, $mac);
        nalepka_text($cr, \$ypos, $fontface, 'normal', 'normal', 1, $invs);
        nalepka_text($cr, \$ypos, $fontface, 'italic', 'normal', 2, $contact);
}
 
 
my @table;
while (<>) {
 chomp;
 my @col = split(/\t/);
 push @table, \@col;
}
 
my ($x, $y) = (0, 0);
 
for my $c (@table) {
        nalepka(nalepka_cr($surface, [$x, $y]), @$c);
 
        $y++;
        if ($y >= $grid[1]) {
                $y = 0; $x++;
                if ($x >= $grid[0]) {
                        my $cr = Cairo::Context->create($surface);
                        $cr->show_page;
                        ($x, $y) = (0, 0);
                }
        }
}
Categories: software Tags: , ,