1 <?php
2 3 4 5 6
7 class Image extends File {
8
9 const ORIENTATION_SQUARE = 0;
10 const ORIENTATION_PORTRAIT = 1;
11 const ORIENTATION_LANDSCAPE = 2;
12
13 static $casting = array(
14 'Tag' => 'HTMLText',
15 );
16
17
18 static $safeGenerateFormats = array('SetRatioSize', 'SetSize', 'SetWidth', 'SetHeight', 'croppedimage');
19
20 21 22 23
24 public static $strip_thumbnail_width = 50;
25
26 27 28 29
30 public static $strip_thumbnail_height = 50;
31
32 33 34 35
36 public static $cms_thumbnail_width = 100;
37
38 39 40
41 public static $cms_thumbnail_height = 100;
42
43 44 45
46 public static $asset_thumbnail_width = 100;
47
48 49 50
51 public static $asset_thumbnail_height = 100;
52
53 54 55
56 public static $asset_preview_width = 400;
57
58 59 60
61 public static $asset_preview_height = 200;
62
63 64 65
66 public function defineMethods() {
67 $methodNames = $this->allMethodNames();
68 foreach($methodNames as $methodName) {
69 if(substr($methodName,0,8) == 'generate') {
70 $this->addWrapperMethod(substr($methodName,8), 'getFormattedImage');
71 }
72 }
73
74 parent::defineMethods();
75 }
76
77 78 79 80
81 public function exists() {
82 if(isset($this->record["Filename"])) {
83 return true;
84 }
85 }
86
87 88 89 90 91 92 93 94
95 96 97 98 99
100 101 102 103
104 function getTag() {
105 if(file_exists(Director::baseFolder() . '/' . $this->Filename)) {
106 $url = $this->getURL();
107 $title = ($this->Title) ? $this->Title : $this->Filename;
108 if($this->Title) {
109 $title = Convert::raw2att($this->Title);
110 } else {
111 if(preg_match("/([^\/]*)\.[a-zA-Z0-9]{1,6}$/", $title, $matches)) $title = Convert::raw2att($matches[1]);
112 }
113 return "<img src=\"$url\" alt=\"$title\" />";
114 }
115 }
116
117 118 119 120
121 function forTemplate() {
122 return $this->getTag();
123 }
124
125 function loadUploadedImage($tmpFile) {
126 if(!is_array($tmpFile)) {
127 user_error("Image::loadUploadedImage() Not passed an array. Most likely, the form hasn't got the right enctype", E_USER_ERROR);
128 }
129
130 if(!$tmpFile['size']) {
131 return;
132 }
133
134 $class = $this->class;
135
136
137 if(!file_exists(ASSETS_PATH)) {
138 mkdir(ASSETS_PATH, Filesystem::$folder_create_mask);
139 }
140
141 if(!file_exists(ASSETS_PATH . "/$class")) {
142 mkdir(ASSETS_PATH . "/$class", Filesystem::$folder_create_mask);
143 }
144
145
146 $file = Convert::rus2lat($tmpFile['name']);
147 $file = str_replace(' ', '-',$file);
148 $file = ereg_replace('[^A-Za-z0-9+.-]+','',$file);
149 $file = ereg_replace('-+', '-',$file);
150 if(!$file) {
151 $file = "file.jpg";
152 }
153
154 $file = ASSETS_PATH . "/$class/$file";
155
156 while(file_exists(BASE_PATH . "/$file")) {
157 $i = $i ? ($i+1) : 2;
158 $oldFile = $file;
159 $file = ereg_replace('[0-9]*(\.[^.]+$)',$i . '\\1', $file);
160 if($oldFile == $file && $i > 2) user_error("Couldn't fix $file with $i", E_USER_ERROR);
161 }
162
163 if(file_exists($tmpFile['tmp_name']) && copy($tmpFile['tmp_name'], BASE_PATH . "/$file")) {
164
165
166 $this->deleteFormattedImages();
167 return true;
168 }
169 }
170
171 public function SetWidth($width) {
172 return $this->getFormattedImage('SetWidth', $width);
173 }
174
175 public function SetHeight($height) {
176 return $this->getFormattedImage('SetHeight', $height);
177 }
178
179 public function SetSize($width, $height) {
180 return $this->getFormattedImage('SetSize', $width, $height);
181 }
182
183 public function SetRatioSize($width, $height) {
184 return $this->getFormattedImage('SetRatioSize', $width, $height);
185 }
186
187 public function generateSetRatioSize(GD $gd, $width, $height) {
188 return $gd->resizeRatio($width, $height);
189 }
190
191 192 193 194
195 public function generateSetWidth(GD $gd, $width) {
196 return $gd->resizeByWidth($width);
197 }
198
199 200 201 202
203 public function generateSetHeight(GD $gd, $height){
204 return $gd->resizeByHeight($height);
205 }
206
207 208 209 210
211 public function generateSetSize(GD $gd, $width, $height) {
212 return $gd->paddedResize($width, $height);
213 }
214
215 public function CMSThumbnail() {
216 return $this->getFormattedImage('CMSThumbnail');
217 }
218
219 220 221 222
223 function generateCMSThumbnail(GD $gd) {
224 return $gd->paddedResize($this->stat('cms_thumbnail_width'),$this->stat('cms_thumbnail_height'));
225 }
226
227 228 229 230
231 function generateAssetLibraryPreview(GD $gd) {
232 return $gd->paddedResize($this->stat('asset_preview_width'),$this->stat('asset_preview_height'));
233 }
234
235 236 237 238
239 function generateAssetLibraryThumbnail(GD $gd) {
240 return $gd->paddedResize($this->stat('asset_thumbnail_width'),$this->stat('asset_thumbnail_height'));
241 }
242
243 244 245 246
247 function generateStripThumbnail(GD $gd) {
248 return $gd->croppedResize($this->stat('strip_thumbnail_width'),$this->stat('strip_thumbnail_height'));
249 }
250
251 function generatePaddedImage(GD $gd, $width, $height) {
252 return $gd->paddedResize($width, $height);
253 }
254
255 256 257 258 259 260 261 262 263
264 function getFormattedImage($format, $arg1 = null, $arg2 = null) {
265 if($this->ID && $this->Filename && Director::fileExists($this->Filename)) {
266 $cacheFile = $this->cacheFilename($format, $arg1, $arg2);
267
268 if(!file_exists(Director::baseFolder().'/'.$cacheFile) || isset($_GET['flush'])) {
269 $this->generateFormattedImage($format, $arg1, $arg2);
270 }
271
272 $cached = new Image_Cached($cacheFile);
273
274 $cached->Title = $this->Title;
275 return $cached;
276 }
277 }
278
279 280 281 282 283 284 285
286 function cacheFilename($format, $arg1 = null, $arg2 = null) {
287 $folder = $this->ParentID ? $this->Parent()->Filename : ASSETS_DIR . "/";
288
289 $format = $format.$arg1.$arg2;
290
291 return $folder . "_resampled/$format-" . $this->Name;
292 }
293
294 295 296 297 298 299 300 301
302 function generateFormattedImage($format, $arg1 = null, $arg2 = null) {
303 $cacheFile = $this->cacheFilename($format, $arg1, $arg2);
304
305 $gd = new GD(Director::baseFolder().'/' . $this->Filename);
306
307 if($gd->hasGD()){
308 $generateFunc = "generate$format";
309 if($this->hasMethod($generateFunc)){
310 $gd2 = $this->$generateFunc($gd, $arg1, $arg2);
311 if($gd2){
312
313 if (array_search($format, Image::$safeGenerateFormats) !== false
314 && $gd->getWidth() == $gd2->getWidth() && $gd->getHeight() == $gd2->getHeight()
315 ) {
316 $gd2->makeDir(dirname(Director::baseFolder().'/' . $cacheFile));
317 copy(Director::baseFolder().'/' . $this->Filename, Director::baseFolder().'/' . $cacheFile);
318 @chmod(Director::baseFolder().'/' . $cacheFile, 0664);
319 }
320 else {
321 $gd2->writeTo(Director::baseFolder().'/' . $cacheFile);
322 }
323 }
324
325 } else {
326 USER_ERROR("Image::generateFormattedImage - Image $format function not found.",E_USER_WARNING);
327 }
328 }
329 }
330
331 332 333 334
335 function generateResizedImage($gd, $width, $height) {
336 if(is_numeric($gd) || !$gd){
337 USER_ERROR("Image::generateFormattedImage - generateResizedImage is being called by legacy code or gd is not set.",E_USER_WARNING);
338 }else{
339 return $gd->resize($width, $height);
340 }
341 }
342
343 344 345 346
347 function generateCroppedImage($gd, $width, $height) {
348 return $gd->croppedResize($width, $height);
349 }
350
351 352 353 354
355 public function generateRotateClockwise(GD $gd) {
356 return $gd->rotate(90);
357 }
358
359 360 361 362
363 public function generateRotateCounterClockwise(GD $gd) {
364 return $gd->rotate(270);
365 }
366
367 368 369 370
371 public function deleteFormattedImages() {
372
373 if(!$this->Filename) return 0;
374 $numDeleted = 0;
375 $folder = $this->ParentID ? $this->Parent()->Filename : ASSETS_DIR . '/';
376 $name = $this->Name;
377
378 if ($this->isChanged('ParentID')) {
379 $folder = dirname($this->getField('Filename')) . '/';
380 $name = basename($this->getField('Filename'));
381 }
382
383 $cacheDir = Director::getAbsFile($folder . '_resampled/');
384 if(!is_dir($cacheDir)) return 0;
385
386 $this->extend('deleteFormattedImages', $numDeleted);
387
388 $cachedFiles = array();
389 if($handle = opendir($cacheDir)) {
390 while(($file = readdir($handle)) !== false) {
391
392 if(substr($file, 0, 1) != '.'
393 && substr_compare($file, $name, -strlen($name), strlen($name)) == 0
394 && is_file($cacheDir . $file)
395 ) {
396 $cachedFiles[] = $file;
397 }
398 }
399 closedir($handle);
400 }
401 if (count($cachedFiles) == 0) return 0;
402
403 $methodNames = $this->allMethodNames();
404 $generateFuncs = array();
405 foreach($methodNames as $methodName) {
406 if(substr($methodName, 0, 8) == 'generate') {
407 $format = substr($methodName, 8);
408 $generateFuncs[] = $format;
409 }
410 }
411
412 $generateFuncs = implode('|', $generateFuncs);
413 $pattern = "/^(({$generateFuncs})(\d+)?-)+".preg_quote($name)."$/i";
414
415 foreach(preg_grep($pattern, $cachedFiles) as $cfile) {
416 if(file_exists($cacheDir . $cfile)) {
417 unlink($cacheDir . $cfile);
418 $numDeleted++;
419 }
420 }
421 return $numDeleted;
422 }
423
424 425 426 427 428 429
430 function getDimensions($dim = "string") {
431 if($this->getField('Filename')) {
432 $imagefile = Director::baseFolder() . '/' . $this->getField('Filename');
433 if(file_exists($imagefile)) {
434 $size = getimagesize($imagefile);
435 return ($dim === "string") ? "$size[0]x$size[1]" : $size[$dim];
436 } else {
437 return ($dim === "string") ? "file '$imagefile' not found" : null;
438 }
439 }
440 }
441
442 443 444 445
446 function getWidth() {
447 return $this->getDimensions(0);
448 }
449
450 451 452 453
454 function getHeight() {
455 return $this->getDimensions(1);
456 }
457
458 459 460 461
462 function getOrientation() {
463 $width = $this->getWidth();
464 $height = $this->getHeight();
465 if($width > $height) {
466 return self::ORIENTATION_LANDSCAPE;
467 } elseif($height > $width) {
468 return self::ORIENTATION_PORTRAIT;
469 } else {
470 return self::ORIENTATION_SQUARE;
471 }
472 }
473
474 475 476 477 478 479
480 function getSVGContent() {
481 if (strtoupper($this->getExtension()) == 'SVG') {
482 if(file_exists($this->getFullPath())) {
483 return file_get_contents($this->getFullPath());
484 }
485 }
486 return false;
487 }
488
489 protected function onBeforeDelete() {
490 parent::onBeforeDelete();
491 $this->deleteFormattedImages();
492 }
493
494
495 protected function resetFilename($renamePhysicalFile = true) {
496 $this->deleteFormattedImages();
497 parent::resetFilename($renamePhysicalFile);
498 }
499 }
500
501 502 503 504 505 506 507
508 class Image_Cached extends Image {
509 510 511 512 513 514
515 public function __construct($filename = null, $isSingleton = false) {
516 parent::__construct(array(), $isSingleton);
517 $this->Filename = $filename;
518 }
519
520 public function getRelativePath() {
521 return $this->getField('Filename');
522 }
523
524
525 public function requireTable() {
526
527 }
528
529 public function debug() {
530 return "Image_Cached object for $this->Filename";
531 }
532 }
533
534
[Raise a SilverStripe Framework issue/bug](https://github.com/silverstripe/silverstripe-framework/issues/new)
- [Raise a SilverStripe CMS issue/bug](https://github.com/silverstripe/silverstripe-cms/issues/new)
- Please use the
Silverstripe Forums to ask development related questions.
-