1<?php 2/* 3 * Gallery - a web based photo album viewer and editor 4 * Copyright (C) 2000-2008 Bharat Mediratta 5 * 6 * This program is free software; you can redistribute it and/or modify 7 * it under the terms of the GNU General Public License as published by 8 * the Free Software Foundation; either version 2 of the License, or (at 9 * your option) any later version. 10 * 11 * This program is distributed in the hope that it will be useful, but 12 * WITHOUT ANY WARRANTY; without even the implied warranty of 13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14 * General Public License for more details. 15 * 16 * You should have received a copy of the GNU General Public License 17 * along with this program; if not, write to the Free Software 18 * Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA. 19 */ 20 21/** 22 * This edit plugin allows you to customize the photo's thumbnail 23 * @package GalleryCore 24 * @subpackage UserInterface 25 * @author Bharat Mediratta <bharat@menalto.com> 26 * @version $Revision: 17580 $ 27 */ 28class ItemEditPhotoThumbnail extends ItemEditPlugin { 29 30 /** 31 * @see ItemEditPlugin::handleRequest 32 */ 33 function handleRequest($form, &$item, &$preferred) { 34 global $gallery; 35 36 $status = null; 37 $error = array(); 38 39 if (isset($form['action']['crop']) || isset($form['action']['reset'])) { 40 /* Load the thumbnail */ 41 list ($ret, $thumbnails) = 42 GalleryCoreApi::fetchThumbnailsByItemIds(array($item->getId())); 43 if ($ret) { 44 return array($ret, null, null, null); 45 } 46 47 if (!empty($thumbnails)) { 48 $thumbnail = $thumbnails[$item->getId()]; 49 } 50 } 51 52 if (isset($form['action']['crop']) && isset($thumbnail)) { 53 /* Get our source */ 54 list ($ret, $source) = GalleryCoreApi::loadEntitiesById( 55 $thumbnail->getDerivativeSourceId(), 56 array('GalleryFileSystemEntity', 'GalleryDerivative')); 57 if ($ret) { 58 return array($ret, null, null, null); 59 } 60 61 list ($ret, $lock) = GalleryCoreApi::acquireWriteLock($thumbnail->getId()); 62 if ($ret) { 63 return array($ret, null, null, null); 64 } 65 66 list ($ret, $thumbnail) = $thumbnail->refresh(); 67 if ($ret) { 68 return array($ret, null, null, null); 69 } 70 71 if (empty($form['crop']['width'])) { 72 $cropX = 0; 73 $cropY = 0; 74 $cropWidth = 100; 75 $cropHeight = 100; 76 } else { 77 /* Sanitize inputs to fit within 0-100 (if cropper miscalculates) */ 78 $cropX = GalleryUtilities::roundToString( 79 max(0, 100 * $form['crop']['x'] / $source->getWidth()), 3); 80 $cropY = GalleryUtilities::roundToString( 81 max(0, 100 * $form['crop']['y'] / $source->getHeight()), 3); 82 $cropWidth = GalleryUtilities::roundToString( 83 min(100, 100 * $form['crop']['width'] / $source->getWidth()), 3); 84 $cropHeight = GalleryUtilities::roundToString( 85 min(100, 100 * $form['crop']['height'] / $source->getHeight()), 3); 86 } 87 88 list ($ret, $operations) = 89 GalleryCoreApi::mergeDerivativeOperations($thumbnail->getDerivativeOperations(), 90 sprintf('crop|%s,%s,%s,%s', 91 $cropX, 92 $cropY, 93 $cropWidth, 94 $cropHeight), 95 true); 96 97 if ($ret) { 98 return array($ret, null, null, null); 99 } 100 $thumbnail->setDerivativeOperations($operations); 101 102 $ret = $thumbnail->save(); 103 if ($ret) { 104 return array($ret, null, null, null); 105 } 106 107 $ret = GalleryCoreApi::releaseLocks($lock); 108 if ($ret) { 109 return array($ret, null, null, null); 110 } 111 112 /* Figure out where to redirect upon success */ 113 list ($ret, $module) = GalleryCoreApi::loadPlugin('module', 'core'); 114 if ($ret) { 115 return array($ret, null, null, null); 116 } 117 $status = $module->translate('Thumbnail cropped successfully'); 118 } else if (isset($form['action']['reset']) && isset($thumbnail)) { 119 list ($ret, $lock) = GalleryCoreApi::acquireWriteLock($thumbnail->getId()); 120 if ($ret) { 121 return array($ret, null, null, null); 122 } 123 124 list ($ret, $thumbnail) = $thumbnail->refresh(); 125 if ($ret) { 126 return array($ret, null, null, null); 127 } 128 129 $operations = GalleryCoreApi::removeDerivativeOperation( 130 'crop', $thumbnail->getDerivativeOperations()); 131 $thumbnail->setDerivativeOperations($operations); 132 133 $ret = $thumbnail->save(); 134 if ($ret) { 135 return array($ret, null, null, null); 136 } 137 138 $ret = GalleryCoreApi::releaseLocks($lock); 139 if ($ret) { 140 return array($ret, null, null, null); 141 } 142 143 /* Figure out where to redirect upon success */ 144 list ($ret, $module) = GalleryCoreApi::loadPlugin('module', 'core'); 145 if ($ret) { 146 return array($ret, null, null, null); 147 } 148 $status = $module->translate('Thumbnail reset successfully'); 149 } 150 151 return array(null, $error, $status, false); 152 } 153 154 /** 155 * @see ItemEditPlugin::loadTemplate 156 */ 157 function loadTemplate(&$template, &$form, $item, $thumbnail) { 158 global $gallery; 159 160 $ItemEditPhotoThumbnail = array(); 161 $ItemEditPhotoThumbnail['showApplet'] = $thumbnail != null; 162 163 list ($ret, $ItemEditPhotoThumbnail['isAdmin']) = GalleryCoreApi::isUserInSiteAdminGroup(); 164 if ($ret) { 165 return array($ret, null, null); 166 } 167 168 if ($form['formName'] != 'ItemEditPhotoThumbnail') { 169 /* First time around, reset the form */ 170 $form['formName'] = 'ItemEditPhotoThumbnail'; 171 } 172 173 $targetThumbnailSize = 0; 174 $crop = array(); 175 if (preg_match('/thumbnail\|(\d+)/', 176 $thumbnail->getDerivativeOperations(), 177 $matches)) { 178 $targetThumbnailSize = $matches[1]; 179 } 180 181 if (preg_match('/crop\|([\d\.]+),([\d\.]+),([\d\.]+),([\d\.]+)/', 182 $thumbnail->getDerivativeOperations(), 183 $matches)) { 184 $crop['leftPercent'] = $matches[1]; 185 $crop['topPercent'] = $matches[2]; 186 $crop['widthPercent'] = $matches[3]; 187 $crop['heightPercent'] = $matches[4]; 188 } else { 189 /* No cropping yet */ 190 $crop['leftPercent'] = 0; 191 $crop['topPercent'] = 0; 192 $crop['widthPercent'] = 100; 193 $crop['heightPercent'] = 100; 194 } 195 196 /* 197 * The source may be quite large. However, it's the only input image that we can really 198 * display at this point because the resized derivatives though they may be smaller, can 199 * have different derivative commands from the source. 200 */ 201 list ($ret, $source) = GalleryCoreApi::loadEntitiesById( 202 $thumbnail->getDerivativeSourceId(), 203 array('GalleryFileSystemEntity', 'GalleryDerivative')); 204 if ($ret) { 205 return array($ret, null, null); 206 } 207 208 /* Convert crop percentages into real pixels */ 209 $crop['left'] = round($crop['leftPercent'] * $source->getWidth() / 100); 210 $crop['top'] = round($crop['topPercent'] * $source->getHeight() / 100); 211 $crop['width'] = round($crop['widthPercent'] * $source->getWidth() / 100); 212 $crop['height'] = round($crop['heightPercent'] * $source->getHeight() / 100); 213 214 /* 215 * It's possible that the source was created before we had an appropriate image toolkit, 216 * so its dimensions can be set to zero, which will cause us problems. In that case, 217 * try rescanning it. 218 */ 219 $width = $source->getWidth(); 220 if (empty($width)) { 221 list ($ret, $lockId) = GalleryCoreApi::acquireWriteLock($source->getId()); 222 if ($ret) { 223 return array($ret, null, null); 224 } 225 list ($ret, $source) = $source->refresh(); 226 if ($ret) { 227 return array($ret, null, null); 228 } 229 $ret = $source->rescan(); 230 if ($ret) { 231 return array($ret, null, null); 232 } 233 $ret = $source->save(); 234 if ($ret) { 235 return array($ret, null, null); 236 } 237 $ret = GalleryCoreApi::releaseLocks($lockId); 238 if ($ret) { 239 return array($ret, null, null); 240 } 241 } 242 243 /* Make sure we have toolkit support */ 244 list ($ret, $toolkit) = 245 GalleryCoreApi::getToolkitByOperation($source->getMimeType(), 'crop'); 246 if ($ret) { 247 return array($ret, null, null); 248 } 249 250 $width = $source->getWidth(); 251 if (empty($width) || !isset($toolkit)) { 252 $ItemEditPhotoThumbnail['editThumbnail']['can']['crop'] = false; 253 } else { 254 $ItemEditPhotoThumbnail['editThumbnail']['can']['crop'] = true; 255 if (empty($crop)) { 256 $crop['left'] = 0; 257 $crop['top'] = 0; 258 $crop['width'] = $source->getWidth(); 259 $crop['height'] = $source->getHeight(); 260 } 261 262 /* 263 * When we make the url for the image, force the session id into it. Otherwise, the 264 * IE JVM will send a request without the session cookie, then the server will make a 265 * new session and send that cookie back to the JVM, which will overwrite the browser's 266 * session with it, effectively logging out the user. 267 */ 268 $urlGenerator =& $gallery->getUrlGenerator(); 269 $url = $urlGenerator->generateUrl( 270 array('view' => 'core.DownloadItem', 'itemId' => $source->getId()), 271 array('forceSessionId' => true, 'forceFullUrl' => true, 'htmlEntities' => false)); 272 273 $ItemEditPhotoThumbnail['editThumbnail']['appletCodeBase'] = 274 GalleryUtilities::convertPathToUrl(dirname(__FILE__)) . '/plugins'; 275 $ItemEditPhotoThumbnail['editThumbnail']['appletJarFile'] = 'ImageCrop.jar'; 276 $ItemEditPhotoThumbnail['editThumbnail']['imageUrl'] = $url; 277 $ItemEditPhotoThumbnail['editThumbnail']['imageWidth'] = $source->getWidth(); 278 $ItemEditPhotoThumbnail['editThumbnail']['imageHeight'] = $source->getHeight(); 279 $ItemEditPhotoThumbnail['editThumbnail']['cropLeft'] = $crop['left']; 280 $ItemEditPhotoThumbnail['editThumbnail']['cropTop'] = $crop['top']; 281 $ItemEditPhotoThumbnail['editThumbnail']['cropWidth'] = $crop['width']; 282 $ItemEditPhotoThumbnail['editThumbnail']['cropHeight'] = $crop['height']; 283 $ItemEditPhotoThumbnail['editThumbnail']['targetThumbnailSize'] = $targetThumbnailSize; 284 285 $aspectlist = array(); 286 list ($ret, $module) = GalleryCoreApi::loadPlugin('module', 'core'); 287 if ($ret) { 288 return array($ret, null, null); 289 } 290 291 $aspectRatioList[] = array('label' => $module->translate('Photo 5x3'), 292 'width' => 5, 293 'height' => 3); 294 $aspectRatioList[] = array('label' => $module->translate('Photo 6x4'), 295 'width' => 6, 296 'height' => 4); 297 $aspectRatioList[] = array('label' => $module->translate('Photo 7x5'), 298 'width' => 7, 299 'height' => 5); 300 $aspectRatioList[] = array('label' => $module->translate('Photo 10x8'), 301 'width' => 10, 302 'height' => 8); 303 $aspectRatioList[] = array('label' => $module->translate('Fullscreen 4x3'), 304 'width' => 4, 305 'height' => 3); 306 $aspectRatioList[] = array('label' => $module->translate('Widescreen 16x9'), 307 'width' => 16, 308 'height' => 9); 309 $aspectRatioList[] = array('label' => $module->translate('CinemaScope 2.35x1'), 310 'width' => 47, 311 'height' => 20); 312 $aspectRatioList[] = array('label' => $module->translate('Square 1x1'), 313 'width' => 1, 314 'height' => 1); 315 $aspectRatioList[] = array('label' => $module->translate('As Image'), 316 'width' => $item->getWidth(), 317 'height' => $item->getHeight()); 318 $ItemEditPhotoThumbnail['editThumbnail']['aspectRatioList'] = $aspectRatioList; 319 320 $orientationList = array(); 321 $orientationList['landscape'] = $module->translate('Landscape'); 322 $orientationList['portrait'] = $module->translate('Portrait'); 323 $ItemEditPhotoThumbnail['editThumbnail']['orientationList'] = $orientationList; 324 325 326 /* 327 * Figure out which aspect ratio / orientation is closest to the current crop 328 * settings so that we can start out with those values selected in the dropdowns. 329 */ 330 $currentAspect = round($crop['width'] / $crop['height'], 2); 331 $i = 0; 332 333 /* Set defaults */ 334 $selectedAspect = 0; 335 $selectedOrientation = 'portrait'; 336 $ItemEditPhotoThumbnail['editThumbnail']['cropRatioWidth'] = 337 $aspectRatioList[0]['width']; 338 $ItemEditPhotoThumbnail['editThumbnail']['cropRatioHeight'] = 339 $aspectRatioList[0]['height']; 340 341 foreach ($aspectRatioList as $aspect) { 342 $landscapeCompare = round($aspect['width'] / $aspect['height'], 2); 343 $portraitCompare = round($aspect['height'] / $aspect['width'], 2); 344 if (abs($currentAspect - $landscapeCompare) <= 0.03) { 345 $selectedAspect = $i; 346 $selectedOrientation = 'landscape'; 347 break; 348 } else if (abs($currentAspect - $portraitCompare) <= 0.03) { 349 $selectedAspect = $i; 350 $selectedOrientation = 'portrait'; 351 break; 352 } 353 $i++; 354 } 355 $ItemEditPhotoThumbnail['editThumbnail']['selectedAspect'] = $selectedAspect; 356 $ItemEditPhotoThumbnail['editThumbnail']['selectedOrientation'] = $selectedOrientation; 357 $ItemEditPhotoThumbnail['editThumbnail']['cropRatioWidth'] = 358 $aspectRatioList[$selectedAspect]['width']; 359 $ItemEditPhotoThumbnail['editThumbnail']['cropRatioHeight'] = 360 $aspectRatioList[$selectedAspect]['height']; 361 } 362 363 $template->style('modules/core/templates/ItemEditPhotoThumbnail.css'); 364 $template->setVariable('ItemEditPhotoThumbnail', $ItemEditPhotoThumbnail); 365 $template->setVariable('controller', 'core.ItemEditPhotoThumbnail'); 366 return array(null, 367 'modules/core/templates/ItemEditPhotoThumbnail.tpl', 'modules_core'); 368 } 369 370 /** 371 * @see ItemEditPlugin::isSupported 372 */ 373 function isSupported($item, $thumbnail) { 374 return ($thumbnail != null && GalleryUtilities::isA($item, 'GalleryPhotoItem')); 375 } 376 377 /** 378 * @see ItemEditPlugin::getTitle 379 */ 380 function getTitle() { 381 list ($ret, $module) = GalleryCoreApi::loadPlugin('module', 'core'); 382 if ($ret) { 383 return array($ret, null); 384 } 385 386 return array(null, $module->translate('Crop Thumbnail')); 387 } 388} 389?> 390