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