#!/usr/bin/env perl
use strict;
use warnings;
use Data::QRCode;
use List::AllUtils qw(min);
use Imager;

sub datapoint2color {
    my ($dp) = @_;

    return 'white' if not $dp->{color};
    return 'black' if $dp->{in_data};
    return 'red' if $dp->{in_format};
    return 'green' if $dp->{in_version};
    return 'blue' if $dp->{in_timing};
    return 'navy' if $dp->{in_alignment};
    return 'web green' if $dp->{in_finder};
    return 'black' if $dp->{in_misc};
}

sub centered {
    my ($x,$y,$scale) = @_;
    my $center_size = int($scale/3);
    my $center_min = int(($scale-$center_size)/2);
    my $center_max = $scale-$center_min;
    return 0 if $x < $center_min;
    return 0 if $x > $center_max;
    return 0 if $y < $center_min;
    return 0 if $y > $center_max;
    return 1;
}

sub overlay_data_to_image {
    my ($data,$src_image) = @_;

    $src_image = $src_image->convert(preset=>'addalpha');
    my $size = min($src_image->getwidth,$src_image->getheight);
    my $data_size = $data->width;
    $size -= ($size % $data_size);

    my $scale = $size / $data_size;
    print "scale=$scale\n";

    my $image = Imager->new(xsize=>$size,ysize=>$size);

    for my $dx (0..$data_size-1) {
        for my $dy (0..$data_size-1) {
            my $dp = $data->data_at($dx,$dy);
            my @data_color = Imager::Color->new(datapoint2color($dp))->rgba;

            if (not $dp->{in_data}) {
                $image->box(
                    xmin => $dx*$scale, ymin => $dy*$scale,
                    xmax => $dx*$scale+$scale-1,
                    ymax => $dy*$scale+$scale-1,
                    filled => 1,
                    color => \@data_color,
                );
            }
            else {
                for my $x_off (0..$scale-1) {
                    for my $y_off (0..$scale-1) {
                        my $img_x = $dx*$scale+$x_off;
                        my $img_y = $dy*$scale+$y_off;

                        my @src_color = $src_image->getpixel(x=>$img_x,y=>$img_y)->rgba;
                        my $alpha = $src_color[3]/255;

                        for my $i (0..2) {
                            $src_color[$i] = int(
                                $src_color[$i]*$alpha
                                    + $data_color[$i]*(1-$alpha)
                            );
                        }
                        my $color = centered($x_off,$y_off,$scale)
                            ? \@data_color
                            : [@src_color[0..2]];
                        $image->setpixel(
                            x => $img_x,
                            y => $img_y,
                            color => $color,
                        );
                    }
                }
            }
        }
    }

    return $image;
}

my $string = 'simple test string, but a bit long just in case we get a too-small QR code';
my $data = Data::QRCode->new(
    input_data => $string,
    error_correction_level => 'H',
);

my $src_img = Imager->new(
    file=>'/tmp/faccione.png',
)->scale(scalefactor=>2,qtype=>'mixing');

my $img = overlay_data_to_image($data,$src_img);
$img->write(file=>'/tmp/qr.png');
