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