package WebGUI::Asset::File::Image; =head1 LEGAL ------------------------------------------------------------------- WebGUI is Copyright 2001-2009 Plain Black Corporation. ------------------------------------------------------------------- Please read the legal notices (docs/legal.txt) and the license (docs/license.txt) that came with this distribution before using this software. ------------------------------------------------------------------- http://www.plainblack.com info@plainblack.com ------------------------------------------------------------------- =cut use strict; use base 'WebGUI::Asset::File'; use WebGUI::Storage; use WebGUI::HTMLForm; use WebGUI::Utility; use WebGUI::Form::Image; =head1 NAME Package WebGUI::Asset::File::Image =head1 DESCRIPTION Extends WebGUI::Asset::File to add image manipulation operations. =head1 SYNOPSIS use WebGUI::Asset::File::Image; =head1 METHODS These methods are available from this class: =cut #------------------------------------------------------------------- =head2 applyConstraints ( options ) Things that are done after a new file is attached. =head3 options A hash reference of optional parameters. =head4 maxImageSize An integer (in pixels) representing the longest edge the image may have. =head4 thumbnailSize An integer (in pixels) representing the longest edge a thumbnail may have. =cut sub applyConstraints { my $self = shift; my $options = shift; $self->SUPER::applyConstraints($options); my $maxImageSize = $options->{maxImageSize} || $self->get('maxImageSize') || $self->session->setting->get("maxImageSize"); my $thumbnailSize = $options->{thumbnailSize} || $self->get('thumbnailSize') || $self->session->setting->get("thumbnailSize"); my $storage = $self->getStorageLocation; my $file = $self->get("filename"); $storage->adjustMaxImageSize($file, $maxImageSize); $self->generateThumbnail($thumbnailSize); $self->setSize; } #------------------------------------------------------------------- =head2 definition ( definition ) Defines the properties of this asset. =head3 definition A hash reference passed in from a subclass definition. =cut sub definition { my $class = shift; my $session = shift; my $definition = shift; my $i18n = WebGUI::International->new($session,"Asset_Image"); push @{$definition}, { assetName => $i18n->get('assetName'), tableName => 'ImageAsset', className => 'WebGUI::Asset::File::Image', icon => 'image.gif', properties => { thumbnailSize => { fieldType => 'integer', defaultValue => $session->setting->get("thumbnailSize"), }, parameters => { fieldType => 'textarea', defaultValue => 'style="border-style:none;"', allowEmpty => 1, }, annotations => { fieldType => 'hidden', noFormPost => 1, defaultValue => '', }, }, }; return $class->SUPER::definition($session,$definition); } #------------------------------------------------------------------- =head2 generateThumbnail ( [ thumbnailSize ] ) Generates a thumbnail for this image. =head3 thumbnailSize A size, in pixels, of the maximum height or width of a thumbnail. If specified this will change the thumbnail size of the image. If unspecified the thumbnail size set in the properties of this asset will be used. =cut sub generateThumbnail { my $self = shift; my $thumbnailSize = shift; if (defined $thumbnailSize) { $self->update({thumbnailSize=>$thumbnailSize}); } $self->getStorageLocation->generateThumbnail($self->get("filename"),$self->get("thumbnailSize")); } #------------------------------------------------------------------- =head2 getEditForm ( ) Returns the TabForm object that will be used in generating the edit page for this asset. =cut sub getEditForm { my $self = shift; my $tabform = $self->SUPER::getEditForm(); # Add the fields defined locally and apply any overrides from the config file my $i18n = WebGUI::International->new($self->session,"Asset_Image"); tie my %extraFields, "Tie::IxHash"; $extraFields{thumbnailSize} = { fieldType => "integer", name => "thumbnailSize", label => $i18n->get('thumbnail size'), hoverHelp => $i18n->get('Thumbnail size description'), value => $self->getValue("thumbnailSize"), }; $extraFields{parameters} = { fieldType => "textarea", name => "parameters", label => $i18n->get('parameters'), hoverHelp => $i18n->get('Parameters description'), value => $self->getValue("parameters"), }; if ($self->get("filename") ne "") { my ($x, $y) = $self->getStorageLocation->getSizeInPixels($self->get("filename")); $extraFields{thumbnail} = { fieldType => "readOnly", label => $i18n->get('thumbnail'), hoverHelp => $i18n->get('Thumbnail description'), value => 'thumbnail' }; $extraFields{imageSize} = { fieldType => "readOnly", label => $i18n->get('image size'), value => $x.' x '.$y, }; } my $overrides = $self->session->config->get("assets/".$self->get("className")); foreach my $fieldName (keys %extraFields) { $self->setupFormField($tabform, $fieldName, \%extraFields, $overrides); } return $tabform; } #------------------------------------------------------------------- =head2 getThumbnailUrl Returns the URL to the thumbnail of the image stored in the Asset. =cut sub getThumbnailUrl { my $self = shift; return $self->getStorageLocation->getThumbnailUrl($self->get("filename")); } #------------------------------------------------------------------- =head2 getToolbar ( ) Returns a toolbar with a set of icons that hyperlink to functions that delete, edit, promote, demote, cut, and copy. =cut sub getToolbar { my $self = shift; return undef if ($self->getToolbarState); return $self->SUPER::getToolbar(); } #------------------------------------------------------------------- =head2 view Renders this asset. =cut sub view { my $self = shift; my $session = $self->session; if (!$session->var->isAdminOn && $self->get("cacheTimeout") > 10) { my $cache = $self->getCache; my $out = $cache->get if defined $cache; return $out if $out; } my %var = %{$self->get}; my ($crop_js, $domMe) = $self->annotate_js({ just_image => 1 }); if ($crop_js) { my ($style, $url) = $session->quick(qw(style url)); $style->setLink($url->extras('yui/build/fonts/fonts-min.css'), {rel=>'stylesheet', type=>'text/css'}); $style->setLink($url->extras('yui/container/assets/container.css'), {rel=>'stylesheet', type=>'text/css'}); $style->setScript($url->extras('yui/build/yahoo-dom-event/yahoo-dom-event.js'), {type=>'text/javascript'}); $style->setScript($url->extras('yui/build/container/container-min.js'), {type=>'text/javascript'}); } $var{controls} = $self->getToolbar; $var{fileUrl} = $self->getFileUrl; $var{fileIcon} = $self->getFileIconUrl; $var{thumbnail} = $self->getThumbnailUrl; $var{annotateJs} = "$crop_js$domMe"; $var{parameters} .= sprintf(q{ id="%s"}, $self->getId()); my $out = $self->processTemplate(\%var,undef,$self->{_viewTemplate}); if (!$session->var->isAdminOn && $self->get("cacheTimeout") > 10) { WebGUI::Cache->new($self->session,"view_".$self->getId)->set($out,$self->get("cacheTimeout")); } return $out; } #---------------------------------------------------------------------------- =head2 setFile ( filename ) Extend the superclass setFile to automatically generate thumbnails. =cut sub setFile { my $self = shift; $self->SUPER::setFile(@_); $self->generateThumbnail; } #------------------------------------------------------------------- =head2 www_edit Override the master class to add image editing controls to the edit screen. Also adds the Image template form variable. =cut sub www_edit { my $self = shift; my $session = $self->session; return $session->privilege->insufficient() unless $self->canEdit; return $session->privilege->locked() unless $self->canEditIfLocked; my $i18n = WebGUI::International->new($session, 'Asset_Image'); if ($self->get('filename')) { my $ac = $self->getAdminConsole; $ac->addSubmenuItem($self->getUrl('func=resize'), $i18n->get("resize image")); $ac->addSubmenuItem($self->getUrl('func=rotate'), $i18n->get("rotate image")); $ac->addSubmenuItem($self->getUrl('func=crop'), $i18n->get("crop image")); $ac->addSubmenuItem($self->getUrl('func=annotate'), $i18n->get("annotate image")); $ac->addSubmenuItem($self->getUrl('func=undo'), $i18n->get("undo image")); } my $tabform = $self->getEditForm; $tabform->getTab("display")->template( -value => $self->get("templateId"), -namespace => "ImageAsset", -hoverHelp => $i18n->get('image template description'), -defaultValue => "PBtmpl0000000000000088", ); return $self->getAdminConsole->render($tabform->print,$i18n->get("edit image")); } #------------------------------------------------------------------- =head2 www_undo Rolls back the last revision of this asset, undoing any work that may have been done to it. =cut sub www_undo { my $self = shift; my $previous = (@{$self->getRevisions()})[1]; if ($previous) { $self->purgeRevision(); $self = $previous; $self->generateThumbnail; } return $self->www_edit(); } #------------------------------------------------------------------- # # All of the images will have to change to support annotate. # The revision system doesn't support the blobs, it seems. # All of the image operations will have to be updated to support annotations. # =head2 www_annotate Allow the user to place some text on their image. This is done via JS and tooltips =cut sub www_annotate { my $self = shift; my $session = $self->session; return $session->privilege->insufficient() unless $self->canEdit; return $session->privilege->locked() unless $self->canEditIfLocked; if (1) { my $newSelf = $self->addRevision(); delete $newSelf->{_storageLocation}; $newSelf->getStorageLocation->annotate($newSelf->get("filename"),$newSelf,$session->form); $newSelf->setSize($newSelf->getStorageLocation->getFileSize($newSelf->get("filename"))); $self = $newSelf; $self->generateThumbnail; WebGUI::VersionTag->autoCommitWorkingIfEnabled($session, { allowComments => 0 }); } my ($style, $url) = $session->quick(qw(style url)); $style->setLink($url->extras('yui/build/resize/assets/skins/sam/resize.css'), {rel=>'stylesheet', type=>'text/css'}); $style->setLink($url->extras('yui/build/fonts/fonts-min.css'), {rel=>'stylesheet', type=>'text/css'}); $style->setLink($url->extras('yui/build/imagecropper/assets/skins/sam/imagecropper.css'), {rel=>'stylesheet', type=>'text/css'}); $style->setScript($url->extras('yui/build/yahoo-dom-event/yahoo-dom-event.js'), {type=>'text/javascript'}); $style->setScript($url->extras('yui/build/element/element-min.js'), {type=>'text/javascript'}); $style->setScript($url->extras('yui/build/dragdrop/dragdrop-min.js'), {type=>'text/javascript'}); $style->setScript($url->extras('yui/build/resize/resize-min.js'), {type=>'text/javascript'}); $style->setScript($url->extras('yui/build/imagecropper/imagecropper-min.js'), {type=>'text/javascript'}); my @pieces = split(/\n/, $self->get('annotations')); my ($img_null, $tooltip_block, $tooltip_none) = ('', '', ''); for (my $i = 0; $i < $#pieces; $i += 3) { $img_null .= "YAHOO.img.container.tt$i = null;\n"; $tooltip_block .= "YAHOO.util.Dom.setStyle('tooltip$i', 'display', 'block');\n"; $tooltip_none .= "YAHOO.util.Dom.setStyle('tooltip$i', 'display', 'none');\n"; my $j = $i + 2; } my $image = '
'.$self->get(
'; my ($width, $height) = $self->getStorageLocation->getSize($self->get("filename")); my @checkboxes = (); my $i18n = WebGUI::International->new($session,"Asset_Image"); my $f = WebGUI::HTMLForm->new($session); $self->getAdminConsole->addSubmenuItem($self->getUrl('func=edit'),$i18n->get("edit image")); $f->hidden( -name=>"func", -value=>"annotate" ); $f->text( -label=>$i18n->get('annotate image'), -value=>'', -hoverHelp=>$i18n->get('annotate image description'), -name=>'annotate_text' ); $f->integer( -label=>$i18n->get('top'), -name=>"annotate_top", -value=>, ); $f->integer( -label=>$i18n->get('left'), -name=>"annotate_left", -value=>, ); $f->integer( -label=>$i18n->get('width'), -name=>"annotate_width", -value=>, ); $f->integer( -label=>$i18n->get('height'), -name=>"annotate_height", -value=>, ); $f->button( -value=>$i18n->get('annotate'), -extras=>'onclick="switchState();"', ); $f->submit; my ($crop_js, $domMe) = $self->annotate_js(); return $self->getAdminConsole->render($f->print."$image$crop_js$domMe",$i18n->get("annotate image")); } #------------------------------------------------------------------- =head2 annotate_js ($opts) Returns some javascript and other supporting text. =head3 $opts A hash reference of options =head4 just_image =cut sub annotate_js { my $self = shift; my $opts = shift; my @pieces = split(/\n/, $self->get('annotations')); # warn("pieces: $#pieces: ". $self->getId()); return "" if !@pieces && $opts->{just_image}; my ($img_null, $tooltip_block, $tooltip_none) = ('', '', ''); for (my $i = 0; $i < $#pieces; $i += 3) { $img_null .= "YAHOO.img.container.tt$i = null;\n"; $tooltip_block .= "YAHOO.util.Dom.setStyle('tooltip$i', 'display', 'block');\n"; $tooltip_none .= "YAHOO.util.Dom.setStyle('tooltip$i', 'display', 'none');\n"; my $j = $i + 2; # warn("i: $i: ", $self->session->form->process("delAnnotate$i")); } my $id = $$opts{just_image} ? $self->getId : "yui_img"; my $crop_js = qq( ); my $hotspots = ''; my $domMe = ''; for (my $i = 0; $i < $#pieces; $i += 3) { my $top_left = $pieces[$i]; my $width_height = $pieces[$i + 1]; my $note = $pieces[$i + 2]; if ($top_left =~ /top: (\d+)px; left: (\d+)px;/) { $top_left = "xy[0]+$1, xy[1]+$2"; } my ($width, $height) = ("", ""); if ($width_height =~ /width: (\d+)px; height: (\d+)px;/) { ($width, $height) = ("$1px", "$2px"); } # next if 3 == $i; $domMe .= qq( ); } return($crop_js, $domMe); } #------------------------------------------------------------------- =head2 www_rotate Displays a form to the user to rotate their image. If the C form variable is true, does the rotation as well. Returns the user to the roate form. =cut sub www_rotate { my $self = shift; my $session = $self->session; return $session->privilege->insufficient() unless $self->canEdit; return $session->privilege->locked() unless $self->canEditIfLocked; if (defined $session->form->process("Rotate")) { my $newSelf = $self->addRevision(); delete $newSelf->{_storageLocation}; $newSelf->getStorageLocation->rotate($newSelf->get("filename"),$session->form->process("Rotate")); $newSelf->setSize($newSelf->getStorageLocation->getFileSize($newSelf->get("filename"))); $self = $newSelf; $self->generateThumbnail; WebGUI::VersionTag->autoCommitWorkingIfEnabled($session, { allowComments => 0 }); } my ($x, $y) = $self->getStorageLocation->getSizeInPixels($self->get("filename")); ##YUI specific datatable CSS my ($style, $url) = $session->quick(qw(style url)); my $img_name = $self->getStorageLocation->getUrl($self->get("filename")); my $img_file = $self->get("filename"); my $image = '
'.$self->get(
'; my $i18n = WebGUI::International->new($session,"Asset_Image"); $self->getAdminConsole->addSubmenuItem($self->getUrl('func=edit'),$i18n->get("edit image")); my $f = WebGUI::HTMLForm->new($session); $f->hidden( -name=>"func", -value=>"rotate" ); $f->button( -value=>"Left", -extras=>qq(onclick="var deg = document.getElementById('Rotate_formId').value; deg = parseInt(deg) + 90; document.getElementById('Rotate_formId').value = deg;"), ); $f->button( -value=>"Right", -extras=>qq(onclick="var deg = document.getElementById('Rotate_formId').value; deg = parseInt(deg) - 90; document.getElementById('Rotate_formId').value = deg;"), ); $f->integer( -label=>$i18n->get('degree'), -name=>"Rotate", -value=>0, ); $f->submit; return $self->getAdminConsole->render($f->print.$image,$i18n->get("rotate image")); } #------------------------------------------------------------------- =head2 www_resize Displays a form for the user to resize this image. If either of the C or C form variables are true, also does the resizing. Returns the user to the resize form. =cut sub www_resize { my $self = shift; my $session = $self->session; return $session->privilege->insufficient() unless $self->canEdit; return $session->privilege->locked() unless $self->canEditIfLocked; if ($session->form->process("newWidth") || $session->form->process("newHeight")) { my $newSelf = $self->addRevision(); delete $newSelf->{_storageLocation}; $newSelf->getStorageLocation->resize($newSelf->get("filename"),$session->form->process("newWidth"),$session->form->process("newHeight")); $newSelf->setSize($newSelf->getStorageLocation->getFileSize($newSelf->get("filename"))); $self = $newSelf; $self->generateThumbnail; WebGUI::VersionTag->autoCommitWorkingIfEnabled($session, { allowComments => 0 }); } my ($x, $y) = $self->getStorageLocation->getSizeInPixels($self->get("filename")); ##YUI specific datatable CSS my ($style, $url) = $session->quick(qw(style url)); $style->setLink($url->extras('yui/build/fonts/fonts-min.css'), {rel=>'stylesheet', type=>'text/css'}); $style->setLink($url->extras('yui/build/resize/assets/skins/sam/resize.css'), {rel=>'stylesheet', type=>'text/css'}); $style->setScript($url->extras('yui/build/yahoo-dom-event/yahoo-dom-event.js'), {type=>'text/javascript'}); $style->setScript($url->extras('yui/build/element/element-min.js'), {type=>'text/javascript'}); $style->setScript($url->extras('yui/build/dragdrop/dragdrop-min.js'), {type=>'text/javascript'}); $style->setScript($url->extras('yui/build/resize/resize-min.js'), {type=>'text/javascript'}); $style->setScript($url->extras('yui/build/animation/animation-min.js'), {type=>'text/javascript'}); my $resize_js = qq( ); my $i18n = WebGUI::International->new($session,"Asset_Image"); $self->getAdminConsole->addSubmenuItem($self->getUrl('func=edit'),$i18n->get("edit image")); my $f = WebGUI::HTMLForm->new($session); $f->hidden( -name=>"func", -value=>"resize" ); $f->readOnly( -label=>$i18n->get('image size'), -hoverHelp=>$i18n->get('image size description'), -value=>$x.' x '.$y, ); $f->integer( -label=>$i18n->get('new width'), -hoverHelp=>$i18n->get('new width description'), -name=>"newWidth", -value=>$x, ); $f->integer( -label=>$i18n->get('new height'), -hoverHelp=>$i18n->get('new height description'), -name=>"newHeight", -value=>$y, ); $f->submit; my $image = '
'.$self->get(
'.$resize_js; return $self->getAdminConsole->render($f->print.$image,$i18n->get("resize image")); } #------------------------------------------------------------------- =head2 www_crop Display a form that allows the user to Crop their images. Also does the cropping if any of the C, C, C or C form variables are true. Returns the user to the cropping form. =cut sub www_crop { my $self = shift; my $session = $self->session; return $session->privilege->insufficient() unless $self->canEdit; return $session->privilege->locked() unless $self->canEditIfLocked; if ($session->form->process("Width") || $session->form->process("Height") || $session->form->process("Top") || $session->form->process("Left")) { my $newSelf = $self->addRevision(); delete $newSelf->{_storageLocation}; $newSelf->getStorageLocation->crop( $newSelf->get("filename"), $session->form->process("Width"), $session->form->process("Height"), $session->form->process("Left"), $session->form->process("Top"), ); $self = $newSelf; $self->generateThumbnail; WebGUI::VersionTag->autoCommitWorkingIfEnabled($session, { allowComments => 0 }); } my $filename = $self->get("filename"); ##YUI specific datatable CSS my ($style, $url) = $session->quick(qw(style url)); my $crop_js = qq( ); $style->setLink($url->extras('yui/build/resize/assets/skins/sam/resize.css'), {rel=>'stylesheet', type=>'text/css'}); $style->setLink($url->extras('yui/build/fonts/fonts-min.css'), {rel=>'stylesheet', type=>'text/css'}); $style->setLink($url->extras('yui/build/imagecropper/assets/skins/sam/imagecropper.css'), {rel=>'stylesheet', type=>'text/css'}); $style->setScript($url->extras('yui/build/yahoo-dom-event/yahoo-dom-event.js'), {type=>'text/javascript'}); $style->setScript($url->extras('yui/build/element/element-min.js'), {type=>'text/javascript'}); $style->setScript($url->extras('yui/build/dragdrop/dragdrop-min.js'), {type=>'text/javascript'}); $style->setScript($url->extras('yui/build/resize/resize-min.js'), {type=>'text/javascript'}); $style->setScript($url->extras('yui/build/imagecropper/imagecropper-min.js'), {type=>'text/javascript'}); my $i18n = WebGUI::International->new($session,"Asset_Image"); $self->getAdminConsole->addSubmenuItem($self->getUrl('func=edit'),$i18n->get("edit image")); my $f = WebGUI::HTMLForm->new($session); $f->hidden( -name=>"degree", -value=>"0" ); $f->hidden( -name=>"func", -value=>"crop" ); my ($x, $y) = $self->getStorageLocation->getSizeInPixels($filename); $f->integer( -label=>$i18n->get('width'), -hoverHelp=>$i18n->get('new width description'), -name=>"Width", -value=>$x, ); $f->integer( -label=>$i18n->get('height'), -hoverHelp=>$i18n->get('new height description'), -name=>"Height", -value=>$y, ); $f->integer( -label=>$i18n->get('top'), -hoverHelp=>$i18n->get('new width description'), -name=>"Top", -value=>$x, ); $f->integer( -label=>$i18n->get('left'), -hoverHelp=>$i18n->get('new height description'), -name=>"Left", -value=>$y, ); $f->submit; my $image = '
'.$filename.'
'.$crop_js; return $self->getAdminConsole->render($f->print.$image,$i18n->get("crop image")); } 1;