SVG support for article images
authorTony Cook <tony@develop-help.com>
Fri, 9 May 2014 06:00:16 +0000 (16:00 +1000)
committerTony Cook <tony@develop-help.com>
Fri, 9 May 2014 06:00:16 +0000 (16:00 +1000)
MANIFEST
site/cgi-bin/modules/BSE/Edit/Article.pm
site/cgi-bin/modules/BSE/ImageHandler/Svg.pm [new file with mode: 0644]
site/cgi-bin/modules/BSE/ImageSize.pm [new file with mode: 0644]
site/cgi-bin/modules/BSE/TB/Image.pm
site/cgi-bin/modules/BSE/TB/Images.pm
site/cgi-bin/modules/BSE/UI/SiteuserCommon.pm

index 660d40c..36b4e19 100644 (file)
--- a/MANIFEST
+++ b/MANIFEST
@@ -111,6 +111,8 @@ site/cgi-bin/modules/BSE/ImageClean.pm
 site/cgi-bin/modules/BSE/ImageHandler/Base.pm
 site/cgi-bin/modules/BSE/ImageHandler/Flash.pm
 site/cgi-bin/modules/BSE/ImageHandler/Img.pm
+site/cgi-bin/modules/BSE/ImageHandler/Svg.pm
+site/cgi-bin/modules/BSE/ImageSize.pm
 site/cgi-bin/modules/BSE/Importer.pm
 site/cgi-bin/modules/BSE/Importer/Source/Base.pm
 site/cgi-bin/modules/BSE/Importer/Source/CSV.pm
index fe3dee1..aa3a351 100644 (file)
@@ -16,7 +16,7 @@ use List::Util qw(first);
 use constant MAX_FILE_DISPLAYNAME_LENGTH => 255;
 use constant ARTICLE_CUSTOM_FIELDS_CFG => "article custom fields";
 
-our $VERSION = "1.045";
+our $VERSION = "1.046";
 
 =head1 NAME
 
@@ -2492,12 +2492,13 @@ sub save_thumbnail {
     close OUTPUT
       or die "Could not close image output file: $!";
 
-    use Image::Size;
+    require BSE::ImageSize;
 
     if ($original && $original->{thumbImage}) {
       #unlink("$imagedir/$original->{thumbImage}");
     }
-    @$newdata{qw/thumbWidth thumbHeight/} = imgsize("$imagedir/$filename");
+    @$newdata{qw/thumbWidth thumbHeight/} =
+      BSE::ImageSize::imgsize("$imagedir/$filename");
     $newdata->{thumbImage} = $filename;
   }
 }
@@ -3353,9 +3354,9 @@ sub _validate_image {
   $imagename =~ /([\w.-]+)$/ and $basename = $1;
 
   # for OSs with special text line endings
-  use Image::Size;
+  require BSE::ImageSize;
 
-  my($width,$height, $type) = imgsize($fh);
+  my ($width,$height, $type) = BSE::ImageSize::imgsize($fh);
 
   unless (defined $width) {
     $$error = "Unknown image file type";
@@ -3903,7 +3904,6 @@ sub req_save_image {
          }
 
          my $full_filename = "$image_dir/$image_name";
-         require Image::Size;
          $delete_file = $image->{image};
          $image->{image} = $image_name;
          $image->{width} = $width;
@@ -4706,6 +4706,7 @@ sub req_save_file {
   my $notes = $cgi->param("notes");
   defined $notes and $file->{notes} = $notes;
   my $name = $cgi->param("name");
+  require BSE::ImageSize;
   if (defined $name) {
     $file->{name} = $name;
     if (length $name) {
@@ -4757,7 +4758,8 @@ sub req_save_file {
        my $up = $cgi->upload($cgi_name);
        if (defined $im && $up) {
          my $data = do { local $/; <$up> };
-         my ($width, $height, $type) = imgsize(\$data);
+         my ($width, $height, $type) =
+           BSE::ImageSize::imgsize(\$data);
 
          if ($width && $height) {
            push @meta,
diff --git a/site/cgi-bin/modules/BSE/ImageHandler/Svg.pm b/site/cgi-bin/modules/BSE/ImageHandler/Svg.pm
new file mode 100644 (file)
index 0000000..f9c71c0
--- /dev/null
@@ -0,0 +1,67 @@
+package BSE::ImageHandler::Svg;
+use strict;
+use base 'BSE::ImageHandler::Img';
+use BSE::Util::HTML;
+use Carp qw(confess);
+
+our $VERSION = "1.000";
+
+sub _make_thumb_hash {
+  my ($self, $geo_id, $im, $static, $abs_urls) = @_;
+
+  my $cfg = $self->cfg;
+  my $debug = $cfg->entry('debug', 'thumbnails', 0);
+
+  $static ||= 0;
+
+  $debug
+    and print STDERR "_make_thumb_hash(..., $geo_id, $im->{src}, ..., $static)\n";
+
+  $geo_id =~ /^[\w,]+$/
+    or return ( undef, "* invalid geometry id *" );
+
+  my $geometry = $cfg->entry('thumb geometries', $geo_id)
+    or return ( undef, "* cannot find thumb geometry $geo_id *" );
+
+  my $thumbs_class = $cfg->entry('editor', 'thumbs_class')
+    or return ( undef, '* no thumbnail engine configured *' );
+
+  (my $thumbs_file = $thumbs_class . ".pm") =~ s!::!/!g;
+  require $thumbs_file;
+  my $thumbs = $thumbs_class->new($cfg);
+
+  $debug
+    and print STDERR "  Thumb class $thumbs_class\n";
+
+  my $error;
+  $thumbs->validate_geometry($geometry, \$error)
+    or return ( undef, "* invalid geometry string: $error *" );
+
+  my %im = map { $_ => $im->{$_} } $im->columns;
+
+  @im{qw/width height type original/} = 
+    $thumbs->thumb_dimensions_sized($geometry, @$im{qw/width height/});
+
+  $im{image} = $im->src;
+
+  if ($abs_urls && $im{image} !~ /^\w+:/) {
+    $im{image} = $cfg->entryVar('site', 'url') . $im{image};
+  }
+
+  $im{src} = $im{image};
+
+  return \%im;
+}
+
+1;
+
+=head1 NAME
+
+BSE::ImageHandler::Svg - handle "image" display for SVG
+
+=head1 DESCRIPTION
+
+This module provides display rendering and limited thumbnail rendering
+for SVG content in the image manager.
+
+=cut
diff --git a/site/cgi-bin/modules/BSE/ImageSize.pm b/site/cgi-bin/modules/BSE/ImageSize.pm
new file mode 100644 (file)
index 0000000..b815e95
--- /dev/null
@@ -0,0 +1,121 @@
+package BSE::ImageSize;
+use strict;
+use Image::Size ();
+use Fcntl ':seek';
+
+our $VERSION = "1.000";
+
+use Exporter 'import';
+use Scalar::Util qw(reftype);
+
+our @EXPORT_OK = qw(imgsize);
+
+=head1 NAME
+
+BSE::ImageSize - wrapper around Image::Size, adds SVG support
+
+=head1 SYNOPSIS
+
+  use BSE::ImageSize "imgsize";
+  my ($width, $height, $type) = imgsize($fh);
+  my ($width, $height, $type) = imgsize($filename);
+  my ($width, $height, $type) = imgsize(\$buf);
+
+=head1 DESCRIPTION
+
+Retrieve the size of the given image file.
+
+On error, returns $width and $height as undef and sets $type to the
+error.
+
+=cut
+
+sub imgsize {
+  my ($fh) = @_;
+
+  my ($width, $height, $type) = Image::Size::imgsize($fh);
+
+  unless (defined $width) {
+    my $info = _parse_svg($fh);
+    if (ref $fh && reftype $fh ne "SCALAR") {
+      seek $fh, 0, SEEK_SET;
+    }
+    unless ($info->{error}) {
+      ($width, $height, $type) = @{$info}{qw(width height file_type)};
+    }
+  }
+
+  return ( $width, $height, $type );
+}
+
+sub _parse_svg {
+  my ($file) = @_;
+
+  require XML::Parser;
+
+  my $io;
+  if (ref $file) {
+    if (reftype $file eq "SCALAR") {
+      # IO::Scalar
+      $io = $$file;
+    }
+    else {
+      $io = $file;
+      binmode $io;
+    }
+  }
+  else {
+    open $io, "<", $file;
+    binmode $file;
+  }
+
+  my ($width, $height, $vb);
+  my $parser = XML::Parser->new
+    (
+     Handlers =>
+     {
+      Start => sub {
+       my ($self, $elem, %attr) = @_;
+
+       if ($elem =~ /\bsvg$/) {
+         $width = $attr{width};
+         $height = $attr{height};
+         $vb = $attr{viewBox};
+         $self->finish;
+       }
+      },
+     },
+    );
+  eval { $parser->parse($io) }
+    or return;
+
+  SKIP:
+  {
+    $width && $height
+      or last SKIP;
+    $width =~ /^(\d+)\s*(px)?$/
+      or last SKIP;
+    $width = $1;
+    $height =~ /^(\d+)\s*(px)?$/
+      or last SKIP;
+    $height = $1;
+    return +{ width => $width, height => $height, file_type => "SVG" };
+  }
+
+  $vb or return;
+
+  ( undef, undef, $width, $height) = split /[\s,]/, $vb;
+  $width && $height
+    or return;
+
+  return +{ width => $width, height => $height, file_type => "SVG" };
+}
+
+1;
+
+=head1 AUTHOR
+
+Tony Cook <tony@develop-help.com>
+
+=cut
+
index a96d2ac..e3387bd 100644 (file)
@@ -8,7 +8,7 @@ use vars qw/@ISA/;
 @ISA = qw/Squirrel::Row BSE::ThumbCommon BSE::TB::TagOwner/;
 use Carp qw(confess);
 
-our $VERSION = "1.008";
+our $VERSION = "1.009";
 
 =head1 NAME
 
@@ -77,8 +77,8 @@ C</image_url()>.
 
 =item ftype
 
-the type of image, either C<img> for normal images, or C<flash> for
-flash files.
+the type of image, either C<img> for normal images, C<svg> for SVG
+images or C<flash> for flash files.
 
 =cut
 
@@ -350,8 +350,8 @@ sub update {
          or die "$msg\n";
 
       my $full_filename = "$image_dir/$image_name";
-      require Image::Size;
-      my ($width, $height, $type) = Image::Size::imgsize($full_filename);
+      require BSE::ImageSize;
+      my ($width, $height, $type) = BSE::ImageSize::imgsize($full_filename);
       if ($width) {
        $delete_file = $image->image;
        $image->set_image($image_name);
index b2d3e91..b699e53 100644 (file)
@@ -6,7 +6,7 @@ use vars qw(@ISA $VERSION);
 @ISA = qw(Squirrel::Table BSE::TB::TagOwners);
 use BSE::TB::Image;
 
-our $VERSION = "1.004";
+our $VERSION = "1.005";
 
 sub rowClass {
   return 'BSE::TB::Image';
@@ -50,6 +50,9 @@ sub get_ftype {
   if ($type eq 'CWS' || $type eq 'SWF') {
     return "flash";
   }
+  elsif ($type eq 'SVG') {
+    return "svg";
+  }
 
   return "img";
 }
index 9a33ddc..7747062 100644 (file)
@@ -3,7 +3,7 @@ use strict;
 use BSE::Util::HTML;
 use BSE::Util::Tags qw(tag_hash);
 
-our $VERSION = "1.000";
+our $VERSION = "1.001";
 
 use constant MAXWIDTH => 10000;
 use constant MAXHEIGHT => 10000;
@@ -31,7 +31,7 @@ sub _save_images {
   my $image_dir = $cfg->entryVar('paths', 'siteuser_images');
 
   require DevHelp::FileUpload;
-  require Image::Size;
+  require BSE::ImageSize;
 
   my @new_files;
 
@@ -63,7 +63,7 @@ sub _save_images {
       push @new_files, $work_fullname;
 
       # image parameter validation
-      my ($width, $height, $type) = Image::Size::imgsize($work_fullname);
+      my ($width, $height, $type) = BSE::ImageSize::imgsize($work_fullname);
       unless (defined $width) {
        $errors->{$file_param} = "Error determining image size: $type";
        unlink $work_fullname;