Dateimanagement: Thumbnails erzeugen und anzeigen
authorBernd Bleßmann <bernd@kivitendo-premium.de>
Wed, 24 Feb 2021 12:10:01 +0000 (13:10 +0100)
committerBernd Bleßmann <bernd@kivitendo-premium.de>
Mon, 15 Mar 2021 07:41:30 +0000 (08:41 +0100)
SL/Controller/File.pm
templates/webpages/file/list.html

index 51dd5c0..1429912 100644 (file)
@@ -8,10 +8,12 @@ use List::Util qw(first max);
 
 use utf8;
 use Encode qw(decode);
+use English qw( -no_match_vars );
 use URI::Escape;
 use Cwd;
 use DateTime;
 use File::stat;
+use File::Slurp qw(slurp);
 use File::Spec::Unix;
 use File::Spec::Win32;
 use File::MimeInfo::Magic;
@@ -29,8 +31,9 @@ use SL::JSON;
 use SL::Helper::CreatePDF qw(:all);
 use SL::Locale::String;
 use SL::SessionFile;
+use SL::SessionFile::Random;
 use SL::File;
-use SL::Controller::Helper::ThumbnailCreator qw(file_probe_image_type);
+use SL::Controller::Helper::ThumbnailCreator qw(file_probe_image_type file_probe_type);
 
 use constant DO_DELETE   => 0;
 use constant DO_UNIMPORT => 1;
@@ -393,6 +396,8 @@ sub _do_list {
   }
   $self->files(\@files);
 
+  $_->{thumbnail} = _create_thumbnail($_) for @files;
+
   if($self->object_type eq 'shop_image'){
     $self->js
       ->run('kivi.ShopPart.show_images', $self->object_id)
@@ -601,6 +606,66 @@ sub _get_sources {
   return @sources;
 }
 
+# ignores all errros
+# todo: cache thumbs?
+sub _create_thumbnail {
+  my ($file) = @_;
+
+  my $filename;
+  if (!eval { $filename = $file->get_file(); 1; }) {
+    $::lxdebug->message(LXDebug::WARN(), "SL::File::_create_thumbnail get_file failed: " . $EVAL_ERROR);
+    return;
+  }
+
+  # Workaround for pfds which are not handled by file_probe_type.
+  # Maybe use mime info stored in db?
+  my $mime_type = File::MimeInfo::Magic::magic($filename);
+  if ($mime_type =~ m{pdf}) {
+    $filename = _convert_pdf_to_png($filename);
+  }
+  return if !$filename;
+
+  my $content;
+  if (!eval { $content = slurp $filename; 1; }) {
+    $::lxdebug->message(LXDebug::WARN(), "SL::File::_create_thumbnail slurp failed: " . $EVAL_ERROR);
+    return;
+  }
+
+  my $ret;
+  if (!eval { $ret = file_probe_type($content); 1; }) {
+    $::lxdebug->message(LXDebug::WARN(), "SL::File::_create_thumbnail file_probe_type failed: " . $EVAL_ERROR);
+    return;
+  }
+
+  # file_probe_type returns a hash ref with thumbnail info and content
+  # or an error message
+  if ('HASH' ne ref $ret) {
+    $::lxdebug->message(LXDebug::WARN(), "SL::File::_create_thumbnail file_probe_type returned an error: " . $ret);
+    return;
+  }
+
+  return $ret;
+}
+
+sub _convert_pdf_to_png {
+  my ($filename) = @_;
+
+  my $sfile = SL::SessionFile::Random->new();
+
+  my $command = 'pdftoppm -singlefile -scale-to 64 -png' . ' ' . $filename . ' ' . $sfile->file_name;
+
+  if (system($command) == -1) {
+    $::lxdebug->message(LXDebug::WARN(), "SL::File::_convert_pdf_to_png: system call failed: " . $ERRNO);
+    return;
+  }
+  if ($CHILD_ERROR) {
+    $::lxdebug->message(LXDebug::WARN(), "SL::File::_convert_pdf_to_png: pdftoppm failed with error code: " . ($CHILD_ERROR >> 8));
+    return;
+  }
+
+  return $sfile->file_name . '.png';
+}
+
 1;
 
 __END__
index dfb59f3..cf56665 100644 (file)
@@ -1,5 +1,7 @@
 [%- USE LxERP -%][% USE L %]
 [% USE T8 %]
+[% USE Base64 %]
+[% USE HTML %]
 [%- IF ! json %]
  <div id="[% file_type %]_list_[% object_type %]">
 [%- END %]
@@ -36,7 +38,7 @@
       </th>
       <th class="listheading" width="30%"><b>[%  LxERP.t8('Description') %]</b></th>
      [%- ELSE %]
-      <th class="listheading" width="40%"></th>
+      <th class="listheading" width="40%"><b>[%  LxERP.t8('ImagePreview') %]</b></th>
      [%- END %]
     </tr>
    </thead>
        </td>
        <td>[% file.description %]</td>
       [%- ELSE %]
-       <td></td>
+       <td align="left">
+        [%- IF file.thumbnail %]
+         <a href="controller.pl?action=File/download&id=[% file.id %][%- IF file.version %]&version=[%- file.version %][%- END %]">
+          <img src="data:[% HTML.escape(file.thumbnail.thumbnail_img_content_type) %];base64,[% file.thumbnail.thumbnail_img_content.encode_base64 %]" alt="[% file.file_name %]">
+         </a>
+        [%- ELSE %]
+         -
+        [%- END %]
+       </td>
       [%- END %]
      </tr>
     [%- END # FOREACH file %]