| 1 | # Movable Type (r) Open Source (C) 2001-2008 Six Apart, Ltd. |
|---|
| 2 | # This program is distributed under the terms of the |
|---|
| 3 | # GNU General Public License, version 2. |
|---|
| 4 | # |
|---|
| 5 | # $Id$ |
|---|
| 6 | |
|---|
| 7 | package MT::Asset::Image; |
|---|
| 8 | |
|---|
| 9 | use strict; |
|---|
| 10 | use base qw( MT::Asset ); |
|---|
| 11 | |
|---|
| 12 | __PACKAGE__->install_properties( { |
|---|
| 13 | class_type => 'image', |
|---|
| 14 | column_defs => { |
|---|
| 15 | 'image_width' => 'integer meta', |
|---|
| 16 | 'image_height' => 'integer meta', |
|---|
| 17 | }, |
|---|
| 18 | } ); |
|---|
| 19 | |
|---|
| 20 | # List of supported file extensions (to aid the stock 'can_handle' method.) |
|---|
| 21 | sub extensions { [ qr/gif/i, qr/jpe?g/i, qr/png/i, ] } |
|---|
| 22 | |
|---|
| 23 | sub class_label { |
|---|
| 24 | MT->translate('Image'); |
|---|
| 25 | } |
|---|
| 26 | |
|---|
| 27 | sub class_label_plural { |
|---|
| 28 | MT->translate('Images'); |
|---|
| 29 | } |
|---|
| 30 | |
|---|
| 31 | sub metadata { |
|---|
| 32 | my $obj = shift; |
|---|
| 33 | my $meta = $obj->SUPER::metadata(@_); |
|---|
| 34 | |
|---|
| 35 | my $width = $obj->image_width; |
|---|
| 36 | my $height = $obj->image_height; |
|---|
| 37 | $meta->{image_width} = $width if defined $width; |
|---|
| 38 | $meta->{image_height} = $height if defined $height; |
|---|
| 39 | $meta->{image_dimensions} = $meta->{ MT->translate("Actual Dimensions") } = |
|---|
| 40 | MT->translate( "[_1] x [_2] pixels", $width, $height ) |
|---|
| 41 | if defined $width && defined $height; |
|---|
| 42 | |
|---|
| 43 | $meta; |
|---|
| 44 | } |
|---|
| 45 | |
|---|
| 46 | sub image_height { |
|---|
| 47 | my $asset = shift; |
|---|
| 48 | my $height = $asset->meta('image_height', @_); |
|---|
| 49 | return $height if $height || @_; |
|---|
| 50 | |
|---|
| 51 | eval { require Image::Size; }; |
|---|
| 52 | return undef if $@; |
|---|
| 53 | my ( $w, $h, $id ) = Image::Size::imgsize($asset->file_path); |
|---|
| 54 | $asset->meta('image_height', $h); |
|---|
| 55 | if ($asset->id) { |
|---|
| 56 | $asset->save; |
|---|
| 57 | } |
|---|
| 58 | return $h; |
|---|
| 59 | } |
|---|
| 60 | |
|---|
| 61 | sub image_width { |
|---|
| 62 | my $asset = shift; |
|---|
| 63 | my $width = $asset->meta('image_width', @_); |
|---|
| 64 | return $width if $width || @_; |
|---|
| 65 | |
|---|
| 66 | eval { require Image::Size; }; |
|---|
| 67 | return undef if $@; |
|---|
| 68 | my ( $w, $h, $id ) = Image::Size::imgsize($asset->file_path); |
|---|
| 69 | $asset->meta('image_width', $w); |
|---|
| 70 | if ($asset->id) { |
|---|
| 71 | $asset->save; |
|---|
| 72 | } |
|---|
| 73 | return $w; |
|---|
| 74 | } |
|---|
| 75 | |
|---|
| 76 | sub has_thumbnail { |
|---|
| 77 | 1; |
|---|
| 78 | } |
|---|
| 79 | |
|---|
| 80 | sub thumbnail_path { |
|---|
| 81 | my $asset = shift; |
|---|
| 82 | my (%param) = @_; |
|---|
| 83 | |
|---|
| 84 | $asset->_make_cache_path($param{Path}); |
|---|
| 85 | } |
|---|
| 86 | |
|---|
| 87 | sub thumbnail_file { |
|---|
| 88 | my $asset = shift; |
|---|
| 89 | my (%param) = @_; |
|---|
| 90 | my $file_path = $asset->file_path; |
|---|
| 91 | my @imginfo = stat($file_path); |
|---|
| 92 | return undef unless @imginfo; |
|---|
| 93 | |
|---|
| 94 | my $blog = $param{Blog} || $asset->blog; |
|---|
| 95 | my $fmgr; |
|---|
| 96 | |
|---|
| 97 | require MT::Util; |
|---|
| 98 | my $asset_cache_path = $asset->_make_cache_path($param{Path}); |
|---|
| 99 | my ( $i_h, $i_w ) = ( $asset->image_height, $asset->image_width ); |
|---|
| 100 | return undef unless $i_h && $i_w; |
|---|
| 101 | |
|---|
| 102 | # Pretend the image is already square, for calculation purposes. |
|---|
| 103 | if ($param{Square}) { |
|---|
| 104 | require MT::Image; |
|---|
| 105 | my %square = MT::Image->inscribe_square( |
|---|
| 106 | Width => $i_w, Height => $i_h ); |
|---|
| 107 | ($i_h, $i_w) = @square{qw( Size Size )}; |
|---|
| 108 | if ( $param{Width} && !$param{Height} ) { |
|---|
| 109 | $param{Height} = $param{Width}; |
|---|
| 110 | } |
|---|
| 111 | elsif ( !$param{Width} && $param{Height} ) { |
|---|
| 112 | $param{Width} = $param{Height}; |
|---|
| 113 | } |
|---|
| 114 | } |
|---|
| 115 | |
|---|
| 116 | if ( my $scale = $param{Scale} ) { |
|---|
| 117 | $param{Width} = int( ( $i_w * $scale ) / 100 ); |
|---|
| 118 | $param{Height} = int( ( $i_h * $scale ) / 100 ); |
|---|
| 119 | } |
|---|
| 120 | if ( !exists $param{Width} && !exists $param{Height} ) { |
|---|
| 121 | $param{Width} = $i_w; |
|---|
| 122 | $param{Height} = $i_h; |
|---|
| 123 | } |
|---|
| 124 | |
|---|
| 125 | # find the longest dimension of the image: |
|---|
| 126 | my ( $n_h, $n_w ) = |
|---|
| 127 | _get_dimension( $i_h, $i_w, $param{Height}, $param{Width} ); |
|---|
| 128 | |
|---|
| 129 | my $file = $asset->thumbnail_filename(%param) or return; |
|---|
| 130 | my $thumbnail = File::Spec->catfile( $asset_cache_path, $file ); |
|---|
| 131 | my @thumbinfo = stat($thumbnail); |
|---|
| 132 | |
|---|
| 133 | # thumbnail file exists and is dated on or later than source image |
|---|
| 134 | if ( @thumbinfo && ( $thumbinfo[9] >= $imginfo[9] ) ) { |
|---|
| 135 | return ( $thumbnail, $n_w, $n_h ); |
|---|
| 136 | } |
|---|
| 137 | |
|---|
| 138 | # stale or non-existent thumbnail. let's create one! |
|---|
| 139 | require MT::FileMgr; |
|---|
| 140 | $fmgr ||= $blog ? $blog->file_mgr : MT::FileMgr->new('Local'); |
|---|
| 141 | return undef unless $fmgr; |
|---|
| 142 | return undef unless $fmgr->can_write($asset_cache_path); |
|---|
| 143 | |
|---|
| 144 | my $data; |
|---|
| 145 | if ( ( $n_w == $i_w ) && ( $n_h == $i_h ) && !$param{Square} |
|---|
| 146 | && !$param{Type} ) { |
|---|
| 147 | $data = $fmgr->get_data( $file_path, 'upload' ); |
|---|
| 148 | } |
|---|
| 149 | else { |
|---|
| 150 | |
|---|
| 151 | # create a thumbnail for this file |
|---|
| 152 | require MT::Image; |
|---|
| 153 | my $img = new MT::Image( Filename => $file_path ) |
|---|
| 154 | or return $asset->error( MT::Image->errstr ); |
|---|
| 155 | |
|---|
| 156 | # Really make the image square, so our scale calculation works out. |
|---|
| 157 | if ($param{Square}) { |
|---|
| 158 | ($data) = $img->make_square() |
|---|
| 159 | or return $asset->error( |
|---|
| 160 | MT->translate( "Error cropping image: [_1]", $img->errstr ) ); |
|---|
| 161 | } |
|---|
| 162 | |
|---|
| 163 | ($data) = $img->scale( Height => $n_h, Width => $n_w ) |
|---|
| 164 | or return $asset->error( |
|---|
| 165 | MT->translate( "Error scaling image: [_1]", $img->errstr ) ); |
|---|
| 166 | |
|---|
| 167 | if (my $type = $param{Type}) { |
|---|
| 168 | ($data) = $img->convert( Type => $type ) |
|---|
| 169 | or return $asset->error( |
|---|
| 170 | MT->translate( "Error converting image: [_1]", $img->errstr ) ); |
|---|
| 171 | } |
|---|
| 172 | } |
|---|
| 173 | $fmgr->put_data( $data, $thumbnail, 'upload' ) |
|---|
| 174 | or return $asset->error( |
|---|
| 175 | MT->translate( "Error creating thumbnail file: [_1]", $fmgr->errstr ) ); |
|---|
| 176 | return ( $thumbnail, $n_w, $n_h ); |
|---|
| 177 | } |
|---|
| 178 | |
|---|
| 179 | sub _get_dimension { |
|---|
| 180 | my ( $i_h, $i_w, $h, $w ) = @_; |
|---|
| 181 | |
|---|
| 182 | my ( $n_h, $n_w ) = ( $i_h, $i_w ); |
|---|
| 183 | my $scale = ''; |
|---|
| 184 | if ( $h && !$w ) { |
|---|
| 185 | $scale = 'h'; |
|---|
| 186 | } |
|---|
| 187 | elsif ( $w && !$h ) { |
|---|
| 188 | $scale = 'w'; |
|---|
| 189 | } |
|---|
| 190 | else { |
|---|
| 191 | if ( $i_h > $i_w ) { |
|---|
| 192 | |
|---|
| 193 | # scale, if necessary, by height |
|---|
| 194 | if ( $i_h > $h ) { |
|---|
| 195 | $scale = 'h'; |
|---|
| 196 | } |
|---|
| 197 | elsif ( $i_w > $w ) { |
|---|
| 198 | $scale = 'w'; |
|---|
| 199 | } |
|---|
| 200 | } |
|---|
| 201 | else { |
|---|
| 202 | |
|---|
| 203 | # scale, if necessary, by width |
|---|
| 204 | if ( $i_w > $w ) { |
|---|
| 205 | $scale = 'w'; |
|---|
| 206 | } |
|---|
| 207 | elsif ( $i_h > $h ) { |
|---|
| 208 | $scale = 'h'; |
|---|
| 209 | } |
|---|
| 210 | } |
|---|
| 211 | } |
|---|
| 212 | if ( $scale eq 'h' ) { |
|---|
| 213 | |
|---|
| 214 | # scale by height |
|---|
| 215 | $n_h = $h; |
|---|
| 216 | $n_w = int( $i_w * $h / $i_h ); |
|---|
| 217 | } |
|---|
| 218 | elsif ( $scale eq 'w' ) { |
|---|
| 219 | |
|---|
| 220 | # scale by width |
|---|
| 221 | $n_w = $w; |
|---|
| 222 | $n_h = int( $i_h * $w / $i_w ); |
|---|
| 223 | } |
|---|
| 224 | return ( $n_h, $n_w ); |
|---|
| 225 | } |
|---|
| 226 | |
|---|
| 227 | sub thumbnail_filename { |
|---|
| 228 | my $asset = shift; |
|---|
| 229 | my (%param) = @_; |
|---|
| 230 | my $file = $asset->file_name or return; |
|---|
| 231 | |
|---|
| 232 | require MT::Util; |
|---|
| 233 | my $format = $param{Format} || MT->translate('%f-thumb-%wx%h-%i%x'); |
|---|
| 234 | my $width = $param{Width} || 'auto'; |
|---|
| 235 | my $height = $param{Height} || 'auto'; |
|---|
| 236 | $file =~ s/\.\w+$//; |
|---|
| 237 | my $base = File::Basename::basename($file); |
|---|
| 238 | my $id = $asset->id; |
|---|
| 239 | my $ext = lc($param{Type}) || $asset->file_ext || ''; |
|---|
| 240 | $ext = '.' . $ext; |
|---|
| 241 | $format =~ s/%w/$width/g; |
|---|
| 242 | $format =~ s/%h/$height/g; |
|---|
| 243 | $format =~ s/%f/$base/g; |
|---|
| 244 | $format =~ s/%i/$id/g; |
|---|
| 245 | $format =~ s/%x/$ext/g; |
|---|
| 246 | return $format; |
|---|
| 247 | } |
|---|
| 248 | |
|---|
| 249 | sub as_html { |
|---|
| 250 | my $asset = shift; |
|---|
| 251 | my ($param) = @_; |
|---|
| 252 | my $text = ''; |
|---|
| 253 | |
|---|
| 254 | $param->{enclose} = 1 unless exists $param->{enclose}; |
|---|
| 255 | |
|---|
| 256 | if ( $param->{include} ) { |
|---|
| 257 | |
|---|
| 258 | my $fname = $asset->file_name; |
|---|
| 259 | require MT::Util; |
|---|
| 260 | |
|---|
| 261 | my $thumb = undef; |
|---|
| 262 | if ( $param->{thumb} ) { |
|---|
| 263 | $thumb = MT::Asset->load( $param->{thumb_asset_id} ) |
|---|
| 264 | || return $asset->error( |
|---|
| 265 | MT->translate( |
|---|
| 266 | "Can't load image #[_1]", |
|---|
| 267 | $param->{thumb_asset_id} |
|---|
| 268 | ) |
|---|
| 269 | ); |
|---|
| 270 | } |
|---|
| 271 | |
|---|
| 272 | my $dimensions = sprintf( |
|---|
| 273 | 'width="%s" height="%s"', |
|---|
| 274 | ( |
|---|
| 275 | $thumb |
|---|
| 276 | ? ( $thumb->image_width, $thumb->image_height ) |
|---|
| 277 | : ( $asset->image_width, $asset->image_height ) |
|---|
| 278 | ) |
|---|
| 279 | ); |
|---|
| 280 | my $wrap_style = ''; |
|---|
| 281 | if ( $param->{wrap_text} && $param->{align} ) { |
|---|
| 282 | $wrap_style = 'class="mt-image-' . $param->{align} . '" '; |
|---|
| 283 | if ( $param->{align} eq 'none' ) { |
|---|
| 284 | $wrap_style .= q{style=""}; |
|---|
| 285 | } |
|---|
| 286 | elsif ( $param->{align} eq 'left' ) { |
|---|
| 287 | $wrap_style .= q{style="float: left; margin: 0 20px 20px 0;"}; |
|---|
| 288 | } |
|---|
| 289 | elsif ( $param->{align} eq 'right' ) { |
|---|
| 290 | $wrap_style .= q{style="float: right; margin: 0 0 20px 20px;"}; |
|---|
| 291 | } |
|---|
| 292 | elsif ( $param->{align} eq 'center' ) { |
|---|
| 293 | $wrap_style .= q{style="text-align: center; display: block; margin: 0 auto 20px;"}; |
|---|
| 294 | } |
|---|
| 295 | } |
|---|
| 296 | |
|---|
| 297 | if ( $param->{popup} && $param->{popup_asset_id} ) { |
|---|
| 298 | my $popup = MT::Asset->load( $param->{popup_asset_id} ) |
|---|
| 299 | || return $asset->error( |
|---|
| 300 | MT->translate( |
|---|
| 301 | "Can't load image #[_1]", |
|---|
| 302 | $param->{popup_asset_id} |
|---|
| 303 | ) |
|---|
| 304 | ); |
|---|
| 305 | my $link = |
|---|
| 306 | $thumb |
|---|
| 307 | ? sprintf( |
|---|
| 308 | '<img src="%s" %s alt="%s" %s />', |
|---|
| 309 | MT::Util::encode_html( $thumb->url ), $dimensions, |
|---|
| 310 | MT::Util::encode_html( $asset->label ), $wrap_style |
|---|
| 311 | ) |
|---|
| 312 | : MT->translate('View image'); |
|---|
| 313 | $text = sprintf( |
|---|
| 314 | q|<a href="%s" onclick="window.open('%s','popup','width=%d,height=%d,scrollbars=no,resizable=no,toolbar=no,directories=no,location=no,menubar=no,status=no,left=0,top=0'); return false">%s</a>|, |
|---|
| 315 | MT::Util::encode_html( $popup->url ), |
|---|
| 316 | MT::Util::encode_html( $popup->url ), |
|---|
| 317 | $asset->image_width, |
|---|
| 318 | $asset->image_height, |
|---|
| 319 | $link, |
|---|
| 320 | ); |
|---|
| 321 | } |
|---|
| 322 | else { |
|---|
| 323 | if ( $param->{thumb} ) { |
|---|
| 324 | $text = sprintf( |
|---|
| 325 | '<a href="%s"><img alt="%s" src="%s" %s %s /></a>', |
|---|
| 326 | MT::Util::encode_html( $asset->url ), |
|---|
| 327 | MT::Util::encode_html( $asset->label ), |
|---|
| 328 | MT::Util::encode_html( $thumb->url ), |
|---|
| 329 | $dimensions, |
|---|
| 330 | $wrap_style, |
|---|
| 331 | ); |
|---|
| 332 | } |
|---|
| 333 | else { |
|---|
| 334 | $text = sprintf( |
|---|
| 335 | '<img alt="%s" src="%s" %s %s />', |
|---|
| 336 | MT::Util::encode_html( $asset->label ), |
|---|
| 337 | MT::Util::encode_html( $asset->url ), |
|---|
| 338 | $dimensions, $wrap_style, |
|---|
| 339 | ); |
|---|
| 340 | } |
|---|
| 341 | } |
|---|
| 342 | } |
|---|
| 343 | else { |
|---|
| 344 | $text = sprintf( |
|---|
| 345 | '<a href="%s">%s</a>', |
|---|
| 346 | MT::Util::encode_html( $asset->url ), |
|---|
| 347 | MT->translate('View image'), |
|---|
| 348 | ); |
|---|
| 349 | } |
|---|
| 350 | |
|---|
| 351 | return $param->{enclose} ? $asset->enclose($text) : $text; |
|---|
| 352 | } |
|---|
| 353 | |
|---|
| 354 | # Return a HTML snippet of form options for inserting this asset |
|---|
| 355 | # into a web page. Default behavior is no options. |
|---|
| 356 | sub insert_options { |
|---|
| 357 | my $asset = shift; |
|---|
| 358 | my ($param) = @_; |
|---|
| 359 | |
|---|
| 360 | my $app = MT->instance; |
|---|
| 361 | my $perms = $app->{perms}; |
|---|
| 362 | my $blog = $asset->blog or return; |
|---|
| 363 | |
|---|
| 364 | eval { require MT::Image; MT::Image->new or die; }; |
|---|
| 365 | $param->{do_thumb} = $@ ? 0 : 1; |
|---|
| 366 | |
|---|
| 367 | $param->{can_save_image_defaults} = $perms->can_save_image_defaults ? 1 : 0; |
|---|
| 368 | |
|---|
| 369 | #$param->{constrain} = $blog->image_default_constrain ? 1 : 0; |
|---|
| 370 | $param->{popup} = $blog->image_default_popup ? 1 : 0; |
|---|
| 371 | $param->{wrap_text} = $blog->image_default_wrap_text ? 1 : 0; |
|---|
| 372 | $param->{make_thumb} = $blog->image_default_thumb ? 1 : 0; |
|---|
| 373 | $param->{ 'align_' . $_ } = |
|---|
| 374 | ( $blog->image_default_align || 'none' ) eq $_ ? 1 : 0 |
|---|
| 375 | for qw(none left center right); |
|---|
| 376 | $param->{ 'unit_w' . $_ } = |
|---|
| 377 | ( $blog->image_default_wunits || 'pixels' ) eq $_ ? 1 : 0 |
|---|
| 378 | for qw(percent pixels); |
|---|
| 379 | $param->{thumb_width} = $blog->image_default_width |
|---|
| 380 | || $asset->image_width |
|---|
| 381 | || 0; |
|---|
| 382 | |
|---|
| 383 | return $app->build_page( 'dialog/asset_options_image.tmpl', $param ); |
|---|
| 384 | } |
|---|
| 385 | |
|---|
| 386 | sub on_upload { |
|---|
| 387 | my $asset = shift; |
|---|
| 388 | my ($param) = @_; |
|---|
| 389 | |
|---|
| 390 | $asset->SUPER::on_upload(@_); |
|---|
| 391 | |
|---|
| 392 | return unless $param->{new_entry}; |
|---|
| 393 | |
|---|
| 394 | my $app = MT->instance; |
|---|
| 395 | require MT::Util; |
|---|
| 396 | |
|---|
| 397 | my $url = $asset->url; |
|---|
| 398 | my $width = $asset->image_width; |
|---|
| 399 | my $height = $asset->image_height; |
|---|
| 400 | |
|---|
| 401 | my ( $base_url, $fname ) = $url =~ m|(.*)/([^/]*)|; |
|---|
| 402 | $url = |
|---|
| 403 | $base_url . '/' |
|---|
| 404 | . $fname; # no need to re-encode filename; url is already encoded |
|---|
| 405 | my $blog = $asset->blog or return; |
|---|
| 406 | my $blog_id = $blog->id; |
|---|
| 407 | |
|---|
| 408 | my ( $thumb, $thumb_width, $thumb_height ); |
|---|
| 409 | $thumb_width = $param->{thumb_width}; |
|---|
| 410 | $thumb = $param->{thumb}; |
|---|
| 411 | if ($thumb) { |
|---|
| 412 | if ( $thumb_width && ( $thumb_width !~ m/^\d+$/ ) ) { |
|---|
| 413 | undef $thumb_width; |
|---|
| 414 | } |
|---|
| 415 | |
|---|
| 416 | # width > 1000 not really a thumbnail, so consider invalid |
|---|
| 417 | if ( $thumb_width > 1000 ) { |
|---|
| 418 | undef $thumb_width; |
|---|
| 419 | } |
|---|
| 420 | } |
|---|
| 421 | if ( $thumb && !$thumb_width ) { |
|---|
| 422 | undef $thumb; |
|---|
| 423 | } |
|---|
| 424 | if ( $param->{image_defaults} ) { |
|---|
| 425 | return $app->error( |
|---|
| 426 | $app->translate( |
|---|
| 427 | 'Permission denied setting image defaults for blog #[_1]', |
|---|
| 428 | $blog_id |
|---|
| 429 | ) |
|---|
| 430 | ) unless $app->{perms}->can_save_image_defaults; |
|---|
| 431 | |
|---|
| 432 | # Save new defaults if requested. |
|---|
| 433 | $blog->image_default_wrap_text( $param->{wrap_text} ? 1 : 0 ); |
|---|
| 434 | $blog->image_default_align( $param->{align} || MT::Blog::ALIGN() ); |
|---|
| 435 | if ($thumb) { |
|---|
| 436 | $blog->image_default_thumb(1); |
|---|
| 437 | $blog->image_default_width($thumb_width); |
|---|
| 438 | $blog->image_default_wunits( $param->{thumb_width_type} |
|---|
| 439 | || MT::Blog::UNITS() ); |
|---|
| 440 | } |
|---|
| 441 | else { |
|---|
| 442 | $blog->image_default_thumb(0); |
|---|
| 443 | $blog->image_default_width(0); |
|---|
| 444 | $blog->image_default_wunits( MT::Blog::UNITS() ); |
|---|
| 445 | } |
|---|
| 446 | |
|---|
| 447 | #$blog->image_default_constrain($param->{constrain} ? 1 : 0); |
|---|
| 448 | $blog->image_default_popup( $param->{popup} ? 1 : 0 ); |
|---|
| 449 | $blog->save or die $blog->errstr; |
|---|
| 450 | } |
|---|
| 451 | |
|---|
| 452 | require MT::Util; |
|---|
| 453 | # Thumbnail creation |
|---|
| 454 | if ( $thumb = $param->{thumb} ) { |
|---|
| 455 | require MT::Image; |
|---|
| 456 | my $image_type = scalar $param->{image_type}; |
|---|
| 457 | my ( $w, $h ) = map $param->{$_}, qw( thumb_width thumb_height ); |
|---|
| 458 | my ($pseudo_thumbnail_url) = |
|---|
| 459 | $asset->thumbnail_url( Height => $h, Width => $w, Pseudo => 1 ); |
|---|
| 460 | my $thumbnail = $asset->thumbnail_filename( Height => $h, Width => $w ); |
|---|
| 461 | my $pseudo_thumbnail_path = File::Spec->catfile( $asset->_make_cache_path( undef, 1 ), $thumbnail ); |
|---|
| 462 | my ( $base, $path, $ext ) = |
|---|
| 463 | File::Basename::fileparse( $thumbnail, qr/[A-Za-z0-9]+$/ ); |
|---|
| 464 | my $img_pkg = MT::Asset->handler_for_file($thumbnail); |
|---|
| 465 | my $original; |
|---|
| 466 | my $asset_thumb = $img_pkg->load({ |
|---|
| 467 | file_name => "$base$ext", |
|---|
| 468 | parent => $asset->id,}); |
|---|
| 469 | if (!$asset_thumb) { |
|---|
| 470 | $asset_thumb = new $img_pkg; |
|---|
| 471 | $original = $asset_thumb->clone; |
|---|
| 472 | $asset_thumb->blog_id($blog_id); |
|---|
| 473 | $asset_thumb->url($pseudo_thumbnail_url); |
|---|
| 474 | $asset_thumb->file_path($pseudo_thumbnail_path); |
|---|
| 475 | $asset_thumb->file_name("$base$ext"); |
|---|
| 476 | $asset_thumb->file_ext($ext); |
|---|
| 477 | $asset_thumb->image_width($w); |
|---|
| 478 | $asset_thumb->image_height($h); |
|---|
| 479 | $asset_thumb->created_by( $app->user->id ); |
|---|
| 480 | $asset_thumb->label($app->translate("Thumbnail image for [_1]", $asset->label || $asset->file_name)); |
|---|
| 481 | $asset_thumb->parent( $asset->id ); |
|---|
| 482 | $asset_thumb->save; |
|---|
| 483 | } else { |
|---|
| 484 | $original = $asset_thumb->clone; |
|---|
| 485 | } |
|---|
| 486 | |
|---|
| 487 | # force these to calculate now, giving a full URL / file path |
|---|
| 488 | # for callbacks |
|---|
| 489 | $thumbnail = $asset_thumb->file_path; |
|---|
| 490 | my $thumbnail_url = $asset_thumb->url; |
|---|
| 491 | my $thumb_file_size = ( stat($thumbnail) )[7]; |
|---|
| 492 | |
|---|
| 493 | $app->run_callbacks( 'cms_post_save.asset', $app, $asset_thumb, |
|---|
| 494 | $original ); |
|---|
| 495 | |
|---|
| 496 | $param->{thumb_asset_id} = $asset_thumb->id; |
|---|
| 497 | |
|---|
| 498 | $app->run_callbacks( |
|---|
| 499 | 'cms_upload_file.' . $asset_thumb->class, |
|---|
| 500 | File => $thumbnail, |
|---|
| 501 | file => $thumbnail, |
|---|
| 502 | Url => $thumbnail_url, |
|---|
| 503 | url => $thumbnail_url, |
|---|
| 504 | Size => $thumb_file_size, |
|---|
| 505 | size => $thumb_file_size, |
|---|
| 506 | Asset => $asset_thumb, |
|---|
| 507 | asset => $asset_thumb, |
|---|
| 508 | Type => 'thumbnail', |
|---|
| 509 | type => 'thumbnail', |
|---|
| 510 | Blog => $blog, |
|---|
| 511 | blog => $blog |
|---|
| 512 | ); |
|---|
| 513 | |
|---|
| 514 | $app->run_callbacks( |
|---|
| 515 | 'cms_upload_image', |
|---|
| 516 | File => $thumbnail, |
|---|
| 517 | file => $thumbnail, |
|---|
| 518 | Url => $thumbnail_url, |
|---|
| 519 | url => $thumbnail_url, |
|---|
| 520 | Asset => $asset_thumb, |
|---|
| 521 | asset => $asset_thumb, |
|---|
| 522 | Width => $w, |
|---|
| 523 | width => $w, |
|---|
| 524 | Height => $h, |
|---|
| 525 | height => $h, |
|---|
| 526 | ImageType => $image_type, |
|---|
| 527 | image_type => $image_type, |
|---|
| 528 | Size => $thumb_file_size, |
|---|
| 529 | size => $thumb_file_size, |
|---|
| 530 | Type => 'thumbnail', |
|---|
| 531 | type => 'thumbnail', |
|---|
| 532 | Blog => $blog, |
|---|
| 533 | blog => $blog |
|---|
| 534 | ); |
|---|
| 535 | } |
|---|
| 536 | if ( $param->{popup} ) { |
|---|
| 537 | require MT::Template; |
|---|
| 538 | if ( |
|---|
| 539 | my $tmpl = MT::Template->load( |
|---|
| 540 | { |
|---|
| 541 | blog_id => $blog_id, |
|---|
| 542 | type => 'popup_image' |
|---|
| 543 | } |
|---|
| 544 | ) |
|---|
| 545 | ) |
|---|
| 546 | { |
|---|
| 547 | ( my $rel_path = $param->{fname} ) =~ s!\.[^.]*$!!; |
|---|
| 548 | if ( $rel_path =~ m!\.\.|\0|\|! ) { |
|---|
| 549 | return $app->error( |
|---|
| 550 | $app->translate( "Invalid basename '[_1]'", $rel_path ) ); |
|---|
| 551 | } |
|---|
| 552 | $rel_path .= '-' . $asset->id; |
|---|
| 553 | my $ext = $blog->file_extension || ''; |
|---|
| 554 | $ext = '.' . $ext if $ext ne ''; |
|---|
| 555 | require MT::Template::Context; |
|---|
| 556 | my $ctx = MT::Template::Context->new; |
|---|
| 557 | $ctx->stash( 'blog', $blog ); |
|---|
| 558 | $ctx->stash( 'blog_id', $blog->id ); |
|---|
| 559 | $ctx->stash( 'asset', $asset ); |
|---|
| 560 | $ctx->stash( 'image_url', $url ); |
|---|
| 561 | $ctx->stash( 'image_width', $width ); |
|---|
| 562 | $ctx->stash( 'image_height', $height ); |
|---|
| 563 | my $popup = $tmpl->build($ctx) or die $tmpl->errstr; |
|---|
| 564 | my $fmgr = $blog->file_mgr; |
|---|
| 565 | my $root_path = $asset->_make_cache_path; |
|---|
| 566 | my $pseudo_path = $asset->_make_cache_path( undef, 1 ); |
|---|
| 567 | my $abs_file_path = |
|---|
| 568 | File::Spec->catfile( $root_path, $rel_path . $ext ); |
|---|
| 569 | |
|---|
| 570 | my ( $i, $rel_path_ext ) = ( 0, $rel_path . $ext ); |
|---|
| 571 | $pseudo_path = File::Spec->catfile( $pseudo_path, $rel_path_ext ); |
|---|
| 572 | my ( $vol, $dirs, $basename ) = |
|---|
| 573 | File::Spec->splitpath($rel_path_ext); |
|---|
| 574 | |
|---|
| 575 | ## Untaint. We have checked for security holes above, so we |
|---|
| 576 | ## should be safe. |
|---|
| 577 | ($abs_file_path) = $abs_file_path =~ /(.+)/s; |
|---|
| 578 | $fmgr->put_data( $popup, $abs_file_path, 'upload' ) |
|---|
| 579 | or return $app->error( |
|---|
| 580 | $app->translate( |
|---|
| 581 | "Error writing to '[_1]': [_2]", $abs_file_path, |
|---|
| 582 | $fmgr->errstr |
|---|
| 583 | ) |
|---|
| 584 | ); |
|---|
| 585 | |
|---|
| 586 | my $html_pkg = MT::Asset->handler_for_file($abs_file_path); |
|---|
| 587 | my $original; |
|---|
| 588 | my $asset_html = $html_pkg->load({ |
|---|
| 589 | file_name => "$basename", |
|---|
| 590 | parent => $asset->id}); |
|---|
| 591 | if (!$asset_html) { |
|---|
| 592 | $asset_html = new $html_pkg; |
|---|
| 593 | $original = $asset_html->clone; |
|---|
| 594 | $asset_html->blog_id($blog_id); |
|---|
| 595 | my $pseudo_url = $pseudo_path; |
|---|
| 596 | $pseudo_url =~ s!\\!/!g; |
|---|
| 597 | $asset_html->url($pseudo_url); |
|---|
| 598 | $asset_html->label($app->translate("Popup Page for [_1]", $asset->label || $asset->file_name)); |
|---|
| 599 | $asset_html->file_path($pseudo_path); |
|---|
| 600 | $asset_html->file_name($basename); |
|---|
| 601 | $asset_html->file_ext( $blog->file_extension ); |
|---|
| 602 | $asset_html->created_by( $app->user->id ); |
|---|
| 603 | $asset_html->parent( $asset->id ); |
|---|
| 604 | $asset_html->save; |
|---|
| 605 | } else { |
|---|
| 606 | $original = $asset_html->clone; |
|---|
| 607 | } |
|---|
| 608 | |
|---|
| 609 | # Select back the real URL for callbacks |
|---|
| 610 | $url = $asset_html->url; |
|---|
| 611 | |
|---|
| 612 | $param->{popup_asset_id} = $asset_html->id; |
|---|
| 613 | |
|---|
| 614 | $app->run_callbacks( 'cms_post_save.asset', $app, $asset_html, |
|---|
| 615 | $original ); |
|---|
| 616 | |
|---|
| 617 | $app->run_callbacks( |
|---|
| 618 | 'cms_upload_file.' . $asset_html->class, |
|---|
| 619 | File => $abs_file_path, |
|---|
| 620 | file => $abs_file_path, |
|---|
| 621 | Url => $url, |
|---|
| 622 | url => $url, |
|---|
| 623 | Asset => $asset_html, |
|---|
| 624 | asset => $asset_html, |
|---|
| 625 | Size => length($popup), |
|---|
| 626 | size => length($popup), |
|---|
| 627 | Type => 'popup', |
|---|
| 628 | type => 'popup', |
|---|
| 629 | Blog => $blog, |
|---|
| 630 | blog => $blog |
|---|
| 631 | ); |
|---|
| 632 | } |
|---|
| 633 | } |
|---|
| 634 | 1; |
|---|
| 635 | } |
|---|
| 636 | |
|---|
| 637 | sub edit_template_param { |
|---|
| 638 | my $asset = shift; |
|---|
| 639 | my ($cb, $app, $param, $tmpl) = @_; |
|---|
| 640 | |
|---|
| 641 | $param->{image_height} = $asset->image_height; |
|---|
| 642 | $param->{image_width} = $asset->image_width; |
|---|
| 643 | } |
|---|
| 644 | |
|---|
| 645 | 1; |
|---|
| 646 | |
|---|
| 647 | __END__ |
|---|
| 648 | |
|---|
| 649 | =head1 NAME |
|---|
| 650 | |
|---|
| 651 | MT::Asset::Image |
|---|
| 652 | |
|---|
| 653 | =head1 SYNOPSIS |
|---|
| 654 | |
|---|
| 655 | use MT::Asset::Image; |
|---|
| 656 | |
|---|
| 657 | # Example |
|---|
| 658 | |
|---|
| 659 | =head1 DESCRIPTION |
|---|
| 660 | |
|---|
| 661 | =head1 METHODS |
|---|
| 662 | |
|---|
| 663 | =head2 MT::Asset::Image->class |
|---|
| 664 | |
|---|
| 665 | Returns 'image', the identifier for this particular class of asset. |
|---|
| 666 | |
|---|
| 667 | =head2 MT::Asset::Image->class_label |
|---|
| 668 | |
|---|
| 669 | Returns the localized descriptive name for this type of asset. |
|---|
| 670 | |
|---|
| 671 | =head2 MT::Asset::Image->extensions |
|---|
| 672 | |
|---|
| 673 | Returns an arrayref of file extensions that are supported by this |
|---|
| 674 | package. |
|---|
| 675 | |
|---|
| 676 | =head2 $asset->metadata |
|---|
| 677 | |
|---|
| 678 | Returns a hashref of metadata values for this asset. |
|---|
| 679 | |
|---|
| 680 | =head2 $asset->thumbnail_file(%param) |
|---|
| 681 | |
|---|
| 682 | Creates or retrieves the file path to a thumbnail image appropriate for |
|---|
| 683 | the asset. If a thumbnail cannot be created, this routine will return |
|---|
| 684 | undef. |
|---|
| 685 | |
|---|
| 686 | =head2 $asset->as_html |
|---|
| 687 | |
|---|
| 688 | Return the HTML I<IMG> element with the image asset attributes. |
|---|
| 689 | |
|---|
| 690 | =head1 AUTHOR & COPYRIGHT |
|---|
| 691 | |
|---|
| 692 | Please see the L<MT/"AUTHOR & COPYRIGHT"> for author, copyright, and |
|---|
| 693 | license information. |
|---|
| 694 | |
|---|
| 695 | =cut |
|---|