Skip to content

Commit

Permalink
[Waste] Limit image size on Echo backed Bulky Collection reports.
Browse files Browse the repository at this point in the history
  • Loading branch information
neprune committed Apr 26, 2024
1 parent 38c6ee2 commit 8f15602
Show file tree
Hide file tree
Showing 4 changed files with 122 additions and 0 deletions.
27 changes: 27 additions & 0 deletions perllib/FixMyStreet/App/Model/PhotoSet.pm
Expand Up @@ -416,4 +416,31 @@ sub redact_image {
return $new_set;
}

# Repeatedly shrink any images over the given size by the given percentage
# until they are small enough.
# Returns the new photoset and a bool indiciating if any images were shrunk.
sub shrink_all_to_size {
my ($self, $size_bytes, $resize_percent) = @_;

Check warning on line 423 in perllib/FixMyStreet/App/Model/PhotoSet.pm

View check run for this annotation

Codecov / codecov/patch

perllib/FixMyStreet/App/Model/PhotoSet.pm#L423

Added line #L423 was not covered by tests

my $shrunk = 0;
my @images = $self->all_ids;
foreach my $i (0.. $#images) {
my $blob = $self->get_raw_image($i)->{data};
while (length $blob > $size_bytes) {
$blob = FixMyStreet::ImageMagick->new(blob => $blob)

Check warning on line 430 in perllib/FixMyStreet/App/Model/PhotoSet.pm

View check run for this annotation

Codecov / codecov/patch

perllib/FixMyStreet/App/Model/PhotoSet.pm#L425-L430

Added lines #L425 - L430 were not covered by tests
->shrink_to_percentage($resize_percent)
->as_blob;
$images[$i] = $blob;
$shrunk = 1;

Check warning on line 434 in perllib/FixMyStreet/App/Model/PhotoSet.pm

View check run for this annotation

Codecov / codecov/patch

perllib/FixMyStreet/App/Model/PhotoSet.pm#L433-L434

Added lines #L433 - L434 were not covered by tests
}
}

my $new_set = (ref $self)->new({

Check warning on line 438 in perllib/FixMyStreet/App/Model/PhotoSet.pm

View check run for this annotation

Codecov / codecov/patch

perllib/FixMyStreet/App/Model/PhotoSet.pm#L438

Added line #L438 was not covered by tests
data_items => \@images,
object => $self->object,
});
$self->delete_cached();
return ($new_set, $shrunk);

Check warning on line 443 in perllib/FixMyStreet/App/Model/PhotoSet.pm

View check run for this annotation

Codecov / codecov/patch

perllib/FixMyStreet/App/Model/PhotoSet.pm#L442-L443

Added lines #L442 - L443 were not covered by tests
}

1;
13 changes: 13 additions & 0 deletions perllib/FixMyStreet/ImageMagick.pm
Expand Up @@ -63,6 +63,19 @@ sub shrink {
return $self->strip;
}

# Shrinks a picture to the specified percentage of the original, but keeping in proportion.
sub shrink_to_percentage {
my ($self, $percentage) = @_;

Check warning on line 68 in perllib/FixMyStreet/ImageMagick.pm

View check run for this annotation

Codecov / codecov/patch

perllib/FixMyStreet/ImageMagick.pm#L68

Added line #L68 was not covered by tests
return $self unless $self->image;

my ($width, $height) = $self->image->Get('width', 'height');
my $new_width = int($width * $percentage / 100);
my $new_height = int($height * $percentage / 100);

Check warning on line 73 in perllib/FixMyStreet/ImageMagick.pm

View check run for this annotation

Codecov / codecov/patch

perllib/FixMyStreet/ImageMagick.pm#L71-L73

Added lines #L71 - L73 were not covered by tests

my $err = $self->image->Scale(width => $new_width, height => $new_height);
return $self->strip;

Check warning on line 76 in perllib/FixMyStreet/ImageMagick.pm

View check run for this annotation

Codecov / codecov/patch

perllib/FixMyStreet/ImageMagick.pm#L75-L76

Added lines #L75 - L76 were not covered by tests
}

# Shrinks a picture to a given dimension (defaults to 90x60(, cropping so that
# it is exactly that.
sub crop {
Expand Down
23 changes: 23 additions & 0 deletions perllib/FixMyStreet/Roles/CobrandEcho.pm
Expand Up @@ -4,13 +4,17 @@ use v5.14;
use warnings;
use DateTime;
use DateTime::Format::Strptime;
use List::Util qw(min);
use Moo::Role;
use POSIX qw(floor);
use Sort::Key::Natural qw(natkeysort_inplace);
use FixMyStreet::DateRange;
use FixMyStreet::DB;
use FixMyStreet::WorkingDays;
use Open311::GetServiceRequestUpdates;

with 'FixMyStreet::Roles::EnforcePhotoSizeOpen311PreSend';

requires 'waste_containers';
requires 'waste_service_to_containers';
requires 'waste_quantity_max';
Expand Down Expand Up @@ -1212,4 +1216,23 @@ sub send_bulky_payment_echo_update_failed {
}
}

around per_photo_size_limit_for_report_in_bytes => sub {
my ($orig, $self, $report, $image_count) = @_;

# We only need to check bulky collections at present.
return $self->$orig($report, $image_count) unless $report->cobrand_data eq 'waste' && $report->contact->category eq 'Bulky collection';

my $cfg = FixMyStreet->config('COBRAND_FEATURES');
return 0 unless $cfg;

my $echo_cfg = $cfg->{'echo'};
return 0 unless $echo_cfg;

my $max_size_per_image = $echo_cfg->{'max_size_per_image_bytes'};
my $max_size_images_total = $echo_cfg->{'max_size_image_total_bytes'};
return 0 unless $max_size_per_image && $max_size_images_total;

return ($max_size_per_image, floor($max_size_images_total / $image_count));
};

1;
59 changes: 59 additions & 0 deletions perllib/FixMyStreet/Roles/EnforcePhotoSizeOpen311PreSend.pm
@@ -0,0 +1,59 @@
package FixMyStreet::Roles::EnforcePhotoSizeOpen311PreSend;
use Moo::Role;

=head1 NAME
FixMyStreet::Roles::EnforcePhotoSizeOpen311PreSend - limit report photo sizes on open311 pre-send
=head1 SYNOPSIS
Applied to a cobrand class to shrink any images larger than a given size as an open311 pre-send action.
Oversized images are repeatedly shrunk until they conform.
A 'photo_size_limit_applied_<bytes>' metadata flag is set on the report to indicate it has been processed
and prevent reprocessing.
=cut

=head1 REQUIRED METHODS
=cut

=head2 per_photo_size_limit_for_report_in_bytes
Takes the report and the number of images.
Returns the max number of bytes for each photo on the report.
0 indicates no max to apply.
=cut

sub per_photo_size_limit_for_report_in_bytes { 0 }

sub open311_pre_send { }

after open311_pre_send => sub {
my ($self, $report, $open311) = @_;
my $photoset = $report->get_photoset;
return unless $photoset->num_images > 0;

my $limit = $self->per_photo_size_limit_for_report_in_bytes($report, $photoset->num_images);
return unless $limit > 0;

my $limit_applied_flag = "photo_size_limit_applied_" . $limit;
return if $report->get_extra_metadata($limit_applied_flag);

# Keep shrinking oversized images to 90% of their original size until they conform.
my ($new, $shrunk) = $photoset->shrink_all_to_size($limit, 90);

if ($shrunk) {
$report->update({ photo => $new });
}

$report->set_extra_metadata( $limit_applied_flag => 1 );
$report->update;
};



1;

0 comments on commit 8f15602

Please sign in to comment.