marei: new koma-names + fallback for outdated versions
[kivitendo-erp.git] / SL / DB / RequirementSpecPicture.pm
1 package SL::DB::RequirementSpecPicture;
2
3 use strict;
4
5 use Carp;
6 use GD;
7 use Image::Info;
8 use List::MoreUtils qw(apply);
9 use List::Util qw(max);
10 use Rose::DB::Object::Util;
11 use SL::DB::MetaSetup::RequirementSpecPicture;
12 use SL::DB::Manager::RequirementSpecPicture;
13 use SL::DB::Helper::ActsAsList;
14 use SL::Locale::String;
15
16 __PACKAGE__->meta->initialize;
17
18 __PACKAGE__->configure_acts_as_list(group_by => [qw(requirement_spec_id text_block_id)]);
19
20 __PACKAGE__->before_save(\&_create_picture_number);
21 __PACKAGE__->before_save(\&_update_thumbnail);
22
23 our %supported_mime_types = (
24   'image/gif'  => { extension => 'gif', convert_to_png => 1, },
25   'image/png'  => { extension => 'png' },
26   'image/jpeg' => { extension => 'jpg' },
27 );
28
29 sub _create_picture_number {
30   my ($self) = @_;
31
32   return 1 if  $self->number;
33   return 0 if !$self->requirement_spec_id;
34
35   my $next_number = $self->requirement_spec->previous_picture_number + 1;
36
37   $self->requirement_spec->update_attributes(previous_picture_number => $next_number) || return 0;
38
39   $self->number($next_number);
40
41   return 1;
42 }
43
44 sub _update_thumbnail {
45   my ($self) = @_;
46
47   return 1 if !$self->picture_content || !$self->picture_content_type || !Rose::DB::Object::Util::get_column_value_modified($self, 'picture_content');
48   $self->create_thumbnail;
49   return 1;
50 }
51
52 sub create_thumbnail {
53   my ($self) = @_;
54
55   croak "No picture set yet" if !$self->picture_content;
56
57   my $image            = GD::Image->new($self->picture_content);
58   my ($width, $height) = $image->getBounds;
59   my $max_dim          = 64;
60   my $curr_max         = max $width, $height, 1;
61   my $factor           = $curr_max <= $max_dim ? 1 : $curr_max / $max_dim;
62   my $new_width        = int($width  / $factor + 0.5);
63   my $new_height       = int($height / $factor + 0.5);
64   my $thumbnail        = GD::Image->new($new_width, $new_height);
65
66   $thumbnail->copyResized($image, 0, 0, 0, 0, $new_width, $new_height, $width, $height);
67
68   $self->thumbnail_content($thumbnail->png);
69   $self->thumbnail_content_type('image/png');
70   $self->thumbnail_width($new_width);
71   $self->thumbnail_height($new_height);
72
73   return 1;
74 }
75
76 sub update_type_and_dimensions {
77   my ($self) = @_;
78
79   return () if !$self->picture_content;
80   return () if $self->picture_content_type && $self->picture_width && $self->picture_height && !Rose::DB::Object::Util::get_column_value_modified($self, 'picture_content');
81
82   my @errors = $self->probe_type;
83   return @errors if @errors;
84
85   my $info = $supported_mime_types{ $self->picture_content_type };
86   if ($info->{convert_to_png}) {
87     $self->picture_content(GD::Image->new($self->picture_content)->png);
88     $self->picture_content_type('image/png');
89     $self->picture_file_name(apply { s/\.[^\.]+$//;  $_ .= '.png'; } $self->picture_file_name);
90   }
91
92   return ();
93 }
94
95 sub probe_type {
96   my ($self) = @_;
97
98   return (t8("No picture uploaded yet")) if !$self->picture_content;
99
100   my $info = Image::Info::image_info(\$self->{picture_content});
101   if (!$info || $info->{error} || !$info->{file_media_type} || !$supported_mime_types{ $info->{file_media_type} }) {
102     $::lxdebug->warn("Image::Info error: " . $info->{error}) if $info && $info->{error};
103     return (t8('Unsupported image type (supported types: #1)', join(' ', sort keys %supported_mime_types)));
104   }
105
106   $self->picture_content_type($info->{file_media_type});
107   $self->picture_width($info->{width});
108   $self->picture_height($info->{height});
109   $self->picture_mtime(DateTime->now_local);
110
111   $self->create_thumbnail;
112
113   return ();
114 }
115
116 sub get_default_file_name_extension {
117   my ($self) = @_;
118
119   my $info = $supported_mime_types{ $self->picture_content_type } || croak("Unsupported content type " . $self->picture_content_type);
120   return $info->{extension};
121 }
122
123 sub validate {
124   my ($self) = @_;
125
126   my @errors;
127
128   push @errors, t8('The file name is missing') if !$self->picture_file_name;
129
130   if (!length($self->picture_content // '')) {
131     push @errors, t8('No picture has been uploaded');
132
133   } else {
134     push @errors, $self->update_type_and_dimensions;
135   }
136
137   return @errors;
138 }
139
140 1;