• このエントリーをはてなブックマークに追加


ss-1391165699

はじめに

そういえば明けましておめでとうございました.

お仕事で書類 PDF 生成とかする際にバーコードの配置が必要なとき, http://blog.iss.ms/2011/02/17/103522 を基にしたアプリケーションを設置して,そこから得られる画像を用いていましたが,もうちょっと寸法的に融通をきかせる必要があるケースがでてきたので.仕様をかじって愚直に実装してみました.あくまでその備忘的なメモであり,今月まだ一度もエントリしていなかったので間にあw(ry

なお,タイトルのとおり,PDF ファイル生成には PDF::API2 を利用しています.

参考

SYNOPSIS

use 5.18.0;
use warnings;
use PDF::API2;
use MyApp::PDF::Barcode::NW7;
 
my $pdf = PDF::API2->new();
$pdf->openpage( 1 )->mediabox( 'A4' );
 
my $bc = MyApp::PDF::Barcode::NW7->new(
    pdf   => $pdf,
    start => 'a',
    stop  => 'a',
);
 
$bc->generate(
    x    => 105.0,  # [mm]
    y    => 148.5,  # [mm]
    h    => 8.0,    # [mm]
    code => '12345678',
);
 
$pdf->saveas( '/path/to/foo.pdf' );

バーコード生成クラス

package MyApp::PDF::Barcode::NW7;
use 5.18.0;
use warnings;
use Mouse;
use MouseX::Types::Mouse qw/Num Str/;
use Data::Validator;
 
use constant +{
    NARROW_WIDTH_MM => .260,       # 「ナロー」の幅 [mm]
    WIDE_WIDTH_MM   => .650,       # 「ワイド」の幅 [mm]
    UNIT_PT         => 25.4 / 72,  # 1pt
    SPACE_COLOR     => '#ffffff',  # 「スペース」の色
    BAR_COLOR       => '#000000',  # 「バー」の色
    CHARACTER_BITS  => 7,
};
 
my %table = (
    '0' => 0b0000011,
    '1' => 0b0000110,
    '2' => 0b0001001,
    '3' => 0b1100000,
    '4' => 0b0010010,
    '5' => 0b1000010,
    '6' => 0b0100001,
    '7' => 0b0100100,
    '8' => 0b0110000,
    '9' => 0b1001000,
    '-' => 0b0001100,
    '$' => 0b0011000,
    '/' => 0b1010001,
    ':' => 0b1000101,
    '+' => 0b0010101,
    '.' => 0b1010100,
    'a' => 0b0011010,
    'b' => 0b0101001,
);
my %bar_width = (
    0 => _mm( NARROW_WIDTH_MM ),
    1 => _mm( WIDE_WIDTH_MM ),
);
my %bar_color = (
    0 => SPACE_COLOR,
    1 => BAR_COLOR,
);
 
has 'pdf'   => ( is => 'ro', isa => 'PDF::API2' );
has 'start' => ( is => 'ro', isa => Str, default => 'a' );
has 'stop'  => ( is => 'ro', isa => Str, default => 'a' );
 
sub generate {
    my ($self, %args) = @_;
    my $v = validator(
        x    => { isa => Num },
        y    => { isa => Num },
        h    => { isa => Num },
        s    => { isa => Num, default => 1.0 },
        code => { isa => Str },
    );
    %args = %{ $v->validate( \%args ) };
 
    my $code  = $args{code};
    my $scale = $args{s};
    my $width = 0;
 
    my @c = map $table{$_}, split //, ( $self->start . $code . $self->stop );
    my $gfx = $self->pdf->openpage( -1 )->gfx();
    my $h = _mm( $args{h} );
    my ($x0, $y0) = ( _mm( $args{x} ), _mm( $args{y} ) );
    my ($x, $y) = ( $x0, $y0 );
 
    my @d = 0 .. (CHARACTER_BITS - 1);
    while ( defined ( my $c = shift @c ) ) {
        my $sb;  # space or bar
        for my $b ( reverse map { ($c >> $_) & 1 } @d ) {
            $sb = $sb ? 0 : 1;
            my $w = $bar_width{$b} * $scale;
            $gfx->fillcolor( $bar_color{$sb} );
            $gfx->rect( $x, $y, $w, $h );
            $gfx->fill();
            $x += $w;
            $width += $w;
        }
        if ( @c ) {
            my $w = $bar_width{0} * $scale;
            $x += $w;  # character gap
            $width += $w;
        }
    }
 
    return _pt( $width );  # [mm]
}
 
 
#
# utilities
#
sub _mm { $_[0] / UNIT_PT }
 
sub _pt { $_[0] * UNIT_PT }
 
sub validator { Data::Validator->new( @_ ) }
 
__PACKAGE__->meta->make_immutable();

おわりに

生成したバーコードは,ちゃんとリーダでも読めているので,とりあえずは問題なさげです.