Health-SHC

 view release on metacpan or  search on metacpan

lib/Health/SHC/Extract.pm  view on Meta::CPAN

use strict;
use warnings;

use File::Which;
# ABSTRACT: Extract the Smart Health Card information from files

use PostScript::Convert;

package Health::SHC::Extract;

our $VERSION = '0.006';

=head1 NAME

Health::SHC::Extract - Extract Smart Health Card QR codes from PDFs or png files.

=head1 SYNOPSIS

    use Health::SHC::Extract;

    my $shc = Health::SHC::Extract->new();

    my @qrcodes = $shc->extract_qr_from_pdf('t/sample-qr-code.pdf');

    my @qrcodes = $shc->extract_qr_from_png('t/sample-qr-code.png');

=head1 DESCRIPTION

This perl module can extract a Smart Health Card's data from QR codes in
PDFs or image files.

The extract_qr_from_pdf function converts a pdf to a png and then calls
extract_qr_from_png.

=cut

=head1 PREREQUISITES

=over

=item * L<PostScript::Convert>

=item * L<File::Temp>

=item * L<Image::Magick>

=item * L<Barcode::ZBar>

=back

=cut

=head1 COPYRIGHT

The following copyright notice applies to all the files provided in
this distribution, including binary files, unless explicitly noted
otherwise.

Copyright 2021 - 2024 Timothy Legge <timlegge@gmail.com>

=head1 LICENCE

This library is free software; you can redistribute it and/or modify
it under the same terms as Perl itself.

=cut

=head2 METHODS

=head3 B<new(...)>

Constructor; see OPTIONS above.

=cut

sub new {
    my $class = shift;

    my $self = {};
    bless $self, $class;
}

=head3 B<extract_qr_from_pdf($filename)>

Extracts any Smart Health Card URI data from the QR codes found
in the PDF file.  It converts the PDF to a png file and extracts
the URIs from the image file by calling extract_qr_from_png.

Arguments:
    $filename:     string filename of a pdf file.

Returns: ARRAY  shc:/ URI from QR code

=cut

sub extract_qr_from_pdf {
    my $self     = shift;
    my $filename = shift;

    if ( ! -e $filename ) {
        return;
    }

    use File::Temp qw/ tempfile tempdir /;
    my ($fh, $output_filename) = tempfile('shctempfileXXXXX', SUFFIX => '.png');

    my $ret;
    eval {
        my $gs_exec = File::Which::which('gs');
        $ret = defined $gs_exec ? 1 : 0;
        PostScript::Convert::psconvert($filename, filename => $output_filename, format => 'pnggray') if $ret;
    };
    return () if (!$ret);

    my @qrcodes = $self->extract_qr_from_png($output_filename);

    unlink $output_filename;
    return @qrcodes;
}

=head3 B<extract_qr_from_png($filename)>

Extracts any Smart Health Card URI data from the QR codes found
in a png file.

Returns an array of shc:/ URIs

Arguments:
    $filename:     string filename of a png file.

Returns: ARRAY  shc:/ URI from QR code

=cut
sub extract_qr_from_png {
    my $self = shift;
    my $filename = shift;

    require Image::Magick;
    require Barcode::ZBar;

    # obtain image data
    my $magick = Image::Magick->new();
    $magick->Read($filename) && die;
    my $raw = $magick->ImageToBlob(magick => 'GRAY', depth => 8);

    # wrap image data
    my $image = Barcode::ZBar::Image->new();
    $image->set_format('Y800');
    my ($col, $rows) = $magick->Get(qw(columns rows));
    $image->set_size($col, $rows);
    $image->set_data($raw);

    # create a reader
    my $scanner = Barcode::ZBar::ImageScanner->new();

    # configure the reader
    $scanner->parse_config("enable");

    # scan the image for barcodes
    my $n = $scanner->scan_image($image);

    # extract results
    my @qrcodes;
    foreach my $symbol ($image->get_symbols()) {
        # do something useful with results
        my $data = $symbol->get_data();

        if ($data =~ /^shc:\//) {
            push (@qrcodes, $data);
        }
    }

    # clean up
    undef($image);
    return @qrcodes;
}
1;



( run in 2.041 seconds using v1.01-cache-2.11-cpan-39bf76dae61 )