| File: | C4/Images.pm |
| Coverage: | 24.8% |
| line | stmt | bran | cond | sub | time | code |
|---|---|---|---|---|---|---|
| 1 | package C4::Images; | |||||
| 2 | ||||||
| 3 | # Copyright (C) 2011 C & P Bibliography Services | |||||
| 4 | # Jared Camins-Esakov <jcamins@cpbibliograpy.com> | |||||
| 5 | # | |||||
| 6 | # This file is part of Koha. | |||||
| 7 | # | |||||
| 8 | # Koha is free software; you can redistribute it and/or modify it under the | |||||
| 9 | # terms of the GNU General Public License as published by the Free Software | |||||
| 10 | # Foundation; either version 2 of the License, or (at your option) any later | |||||
| 11 | # version. | |||||
| 12 | # | |||||
| 13 | # Koha is distributed in the hope that it will be useful, but WITHOUT ANY | |||||
| 14 | # WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR | |||||
| 15 | # A PARTICULAR PURPOSE. See the GNU General Public License for more details. | |||||
| 16 | # | |||||
| 17 | # You should have received a copy of the GNU General Public License along | |||||
| 18 | # with Koha; if not, write to the Free Software Foundation, Inc., | |||||
| 19 | # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. | |||||
| 20 | ||||||
| 21 | 1 1 1 | 274 27 47 | use strict; | |||
| 22 | 1 1 1 | 5 2 29 | use warnings; | |||
| 23 | 1 1 1 1 1 1 | 120 52 18 4 2 13 | use 5.010; | |||
| 24 | ||||||
| 25 | 1 1 1 | 4 2 10 | use C4::Context; | |||
| 26 | 1 1 1 | 206 8800 314 | use GD; | |||
| 27 | ||||||
| 28 | 1 1 1 | 33 25 178 | use vars qw($debug $noimage $VERSION @ISA @EXPORT); | |||
| 29 | ||||||
| 30 | BEGIN { | |||||
| 31 | ||||||
| 32 | # set the version for version checking | |||||
| 33 | 1 | 21 | $VERSION = 3.03; | |||
| 34 | 1 | 22 | require Exporter; | |||
| 35 | 1 | 26 | @ISA = qw(Exporter); | |||
| 36 | 1 | 19 | @EXPORT = qw( | |||
| 37 | &PutImage | |||||
| 38 | &RetrieveImage | |||||
| 39 | &ListImagesForBiblio | |||||
| 40 | &DelImage | |||||
| 41 | ); | |||||
| 42 | 1 | 44 | $debug = $ENV{KOHA_DEBUG} || $ENV{DEBUG} || 0; | |||
| 43 | ||||||
| 44 | 1 | 1145 | $noimage = pack( "H*", | |||
| 45 | '47494638396101000100800000FFFFFF' | |||||
| 46 | . '00000021F90401000000002C00000000' | |||||
| 47 | . '010001000002024401003B' ); | |||||
| 48 | } | |||||
| 49 | ||||||
| 50 - 56 | =head2 PutImage
PutImage($biblionumber, $srcimage, $replace);
Stores binary image data and thumbnail in database, optionally replacing existing images for the given biblio.
=cut | |||||
| 57 | ||||||
| 58 | sub PutImage { | |||||
| 59 | 0 | my ( $biblionumber, $srcimage, $replace ) = @_; | ||||
| 60 | ||||||
| 61 | 0 | return -1 unless defined($srcimage); | ||||
| 62 | ||||||
| 63 | 0 | if ($replace) { | ||||
| 64 | 0 | foreach ( ListImagesForBiblio($biblionumber) ) { | ||||
| 65 | 0 | DelImage($_); | ||||
| 66 | } | |||||
| 67 | } | |||||
| 68 | ||||||
| 69 | 0 | my $dbh = C4::Context->dbh; | ||||
| 70 | 0 | my $query = | ||||
| 71 | "INSERT INTO biblioimages (biblionumber, mimetype, imagefile, thumbnail) VALUES (?,?,?,?);"; | |||||
| 72 | 0 | my $sth = $dbh->prepare($query); | ||||
| 73 | ||||||
| 74 | 0 | my $mimetype = 'image/png' | ||||
| 75 | ; # GD autodetects three basic image formats: PNG, JPEG, XPM; we will convert all to PNG which is lossless... | |||||
| 76 | ||||||
| 77 | # Check the pixel size of the image we are about to import... | |||||
| 78 | 0 | my $thumbnail = _scale_image( $srcimage, 140, 200 ) | ||||
| 79 | ; # MAX pixel dims are 140 X 200 for thumbnail... | |||||
| 80 | 0 | my $fullsize = _scale_image( $srcimage, 600, 800 ) | ||||
| 81 | ; # MAX pixel dims are 600 X 800 for full-size image... | |||||
| 82 | 0 | $debug and warn "thumbnail is " . length($thumbnail) . " bytes."; | ||||
| 83 | ||||||
| 84 | 0 | $sth->execute( $biblionumber, $mimetype, $fullsize->png(), | ||||
| 85 | $thumbnail->png() ); | |||||
| 86 | 0 | my $dberror = $sth->errstr; | ||||
| 87 | 0 | warn "Error returned inserting $biblionumber.$mimetype." if $sth->errstr; | ||||
| 88 | 0 | undef $thumbnail; | ||||
| 89 | 0 | undef $fullsize; | ||||
| 90 | 0 | return $dberror; | ||||
| 91 | } | |||||
| 92 | ||||||
| 93 - 98 | =head2 RetrieveImage
my ($imagedata, $error) = RetrieveImage($imagenumber);
Retrieves the specified image.
=cut | |||||
| 99 | ||||||
| 100 | sub RetrieveImage { | |||||
| 101 | 0 | my ($imagenumber) = @_; | ||||
| 102 | ||||||
| 103 | 0 | my $dbh = C4::Context->dbh; | ||||
| 104 | 0 | my $query = | ||||
| 105 | 'SELECT mimetype, imagefile, thumbnail FROM biblioimages WHERE imagenumber = ?'; | |||||
| 106 | 0 | my $sth = $dbh->prepare($query); | ||||
| 107 | 0 | $sth->execute($imagenumber); | ||||
| 108 | 0 | my $imagedata = $sth->fetchrow_hashref; | ||||
| 109 | 0 | if ( !$imagedata ) { | ||||
| 110 | 0 | $imagedata->{'thumbnail'} = $noimage; | ||||
| 111 | 0 | $imagedata->{'imagefile'} = $noimage; | ||||
| 112 | } | |||||
| 113 | 0 | if ( $sth->err ) { | ||||
| 114 | 0 | warn "Database error!" if $debug; | ||||
| 115 | } | |||||
| 116 | 0 | return $imagedata; | ||||
| 117 | } | |||||
| 118 | ||||||
| 119 - 124 | =head2 ListImagesForBiblio
my (@images) = ListImagesForBiblio($biblionumber);
Gets a list of all images associated with a particular biblio.
=cut | |||||
| 125 | ||||||
| 126 | sub ListImagesForBiblio { | |||||
| 127 | 0 | my ($biblionumber) = @_; | ||||
| 128 | ||||||
| 129 | 0 | my @imagenumbers; | ||||
| 130 | 0 | my $dbh = C4::Context->dbh; | ||||
| 131 | 0 | my $query = 'SELECT imagenumber FROM biblioimages WHERE biblionumber = ?'; | ||||
| 132 | 0 | my $sth = $dbh->prepare($query); | ||||
| 133 | 0 | $sth->execute($biblionumber); | ||||
| 134 | 0 | warn "Database error!" if $sth->errstr; | ||||
| 135 | 0 | if ( !$sth->errstr && $sth->rows > 0 ) { | ||||
| 136 | 0 | while ( my $row = $sth->fetchrow_hashref ) { | ||||
| 137 | 0 | push @imagenumbers, $row->{'imagenumber'}; | ||||
| 138 | } | |||||
| 139 | 0 | return @imagenumbers; | ||||
| 140 | } | |||||
| 141 | else { | |||||
| 142 | 0 | return undef; | ||||
| 143 | } | |||||
| 144 | } | |||||
| 145 | ||||||
| 146 - 152 | =head2 DelImage
my ($dberror) = DelImage($imagenumber);
Removes the image with the supplied imagenumber.
=cut | |||||
| 153 | ||||||
| 154 | sub DelImage { | |||||
| 155 | 0 | my ($imagenumber) = @_; | ||||
| 156 | 0 | warn "Imagenumber passed to DelImage is $imagenumber" if $debug; | ||||
| 157 | 0 | my $dbh = C4::Context->dbh; | ||||
| 158 | 0 | my $query = "DELETE FROM biblioimages WHERE imagenumber = ?;"; | ||||
| 159 | 0 | my $sth = $dbh->prepare($query); | ||||
| 160 | 0 | $sth->execute($imagenumber); | ||||
| 161 | 0 | my $dberror = $sth->errstr; | ||||
| 162 | 0 | warn "Database error!" if $sth->errstr; | ||||
| 163 | 0 | return $dberror; | ||||
| 164 | } | |||||
| 165 | ||||||
| 166 | sub _scale_image { | |||||
| 167 | 0 | my ( $image, $maxwidth, $maxheight ) = @_; | ||||
| 168 | 0 | my ( $width, $height ) = $image->getBounds(); | ||||
| 169 | 0 | $debug and warn "image is $width pix X $height pix."; | ||||
| 170 | 0 | if ( $width > $maxwidth || $height > $maxheight ) { | ||||
| 171 | ||||||
| 172 | # $debug and warn "$filename exceeds the maximum pixel dimensions of $maxwidth X $maxheight. Resizing..."; | |||||
| 173 | 0 | my $percent_reduce; # Percent we will reduce the image dimensions by... | ||||
| 174 | 0 | if ( $width > $maxwidth ) { | ||||
| 175 | 0 | $percent_reduce = | ||||
| 176 | sprintf( "%.5f", ( $maxwidth / $width ) ) | |||||
| 177 | ; # If the width is oversize, scale based on width overage... | |||||
| 178 | } | |||||
| 179 | else { | |||||
| 180 | 0 | $percent_reduce = | ||||
| 181 | sprintf( "%.5f", ( $maxheight / $height ) ) | |||||
| 182 | ; # otherwise scale based on height overage. | |||||
| 183 | } | |||||
| 184 | 0 | my $width_reduce = sprintf( "%.0f", ( $width * $percent_reduce ) ); | ||||
| 185 | 0 | my $height_reduce = sprintf( "%.0f", ( $height * $percent_reduce ) ); | ||||
| 186 | 0 | $debug | ||||
| 187 | and warn "Reducing image by " | |||||
| 188 | . ( $percent_reduce * 100 ) | |||||
| 189 | . "\% or to $width_reduce pix X $height_reduce pix"; | |||||
| 190 | 0 | my $newimage = GD::Image->new( $width_reduce, $height_reduce, 1 ) | ||||
| 191 | ; #'1' creates true color image... | |||||
| 192 | 0 | $newimage->copyResampled( $image, 0, 0, 0, 0, $width_reduce, | ||||
| 193 | $height_reduce, $width, $height ); | |||||
| 194 | 0 | return $newimage; | ||||
| 195 | } | |||||
| 196 | else { | |||||
| 197 | 0 | return $image; | ||||
| 198 | } | |||||
| 199 | } | |||||
| 200 | ||||||
| 201 - 208 | =head2 NoImage
C4::Images->NoImage;
Returns the gif to be used when there is no image matching the request, and
its mimetype (image/gif).
=cut | |||||
| 209 | ||||||
| 210 | sub NoImage { | |||||
| 211 | 0 | return $noimage, 'image/gif'; | ||||
| 212 | } | |||||
| 213 | ||||||
| 214 | 1; | |||||