/** * Process image and write the result in the image cache. * * If the image already exists in cache, the cache file is immediately returned, without any processing * If the original (full resolution) image is required, create either a symbolic link with the * original image in the cache dir, or copy it in the cache dir. * * This method updates the cache_file_path and file_url attributes of the event * * @param ImageEvent $event * @param string $eventName * @param EventDispatcherInterface $dispatcher * * @throws \Thelia\Exception\ImageException * @throws \InvalidArgumentException */ public function processImage(ImageEvent $event, $eventName, EventDispatcherInterface $dispatcher) { $subdir = $event->getCacheSubdirectory(); $source_file = $event->getSourceFilepath(); if (null == $subdir || null == $source_file) { throw new \InvalidArgumentException("Cache sub-directory and source file path cannot be null"); } // Find cached file path $cacheFilePath = $this->getCacheFilePath($subdir, $source_file, $event->isOriginalImage(), $event->getOptionsHash()); $originalImagePathInCache = $this->getCacheFilePath($subdir, $source_file, true); if (!file_exists($cacheFilePath)) { if (!file_exists($source_file)) { throw new ImageException(sprintf("Source image file %s does not exists.", $source_file)); } // Create a cached version of the original image in the web space, if not exists if (!file_exists($originalImagePathInCache)) { $mode = ConfigQuery::read('original_image_delivery_mode', 'symlink'); if ($mode == 'symlink') { if (false === symlink($source_file, $originalImagePathInCache)) { throw new ImageException(sprintf("Failed to create symbolic link for %s in %s image cache directory", basename($source_file), $subdir)); } } else { // mode = 'copy' if (false === @copy($source_file, $originalImagePathInCache)) { throw new ImageException(sprintf("Failed to copy %s in %s image cache directory", basename($source_file), $subdir)); } } } // Process image only if we have some transformations to do. if (!$event->isOriginalImage()) { // We have to process the image. $imagine = $this->createImagineInstance(); $image = $imagine->open($source_file); if ($image) { // Allow image pre-processing (watermarging, or other stuff...) $event->setImageObject($image); $dispatcher->dispatch(TheliaEvents::IMAGE_PREPROCESSING, $event); $image = $event->getImageObject(); $background_color = $event->getBackgroundColor(); $palette = new RGB(); if ($background_color != null) { $bg_color = $palette->color($background_color); } else { // Define a fully transparent white background color $bg_color = $palette->color('fff', 0); } // Apply resize $image = $this->applyResize($imagine, $image, $event->getWidth(), $event->getHeight(), $event->getResizeMode(), $bg_color, $event->getAllowZoom()); // Rotate if required $rotation = intval($event->getRotation()); if ($rotation != 0) { $image->rotate($rotation, $bg_color); } // Flip // Process each effects foreach ($event->getEffects() as $effect) { $effect = trim(strtolower($effect)); $params = explode(':', $effect); switch ($params[0]) { case 'greyscale': case 'grayscale': $image->effects()->grayscale(); break; case 'negative': $image->effects()->negative(); break; case 'horizontal_flip': case 'hflip': $image->flipHorizontally(); break; case 'vertical_flip': case 'vflip': $image->flipVertically(); break; case 'gamma': // Syntax: gamma:value. Exemple: gamma:0.7 if (isset($params[1])) { $gamma = floatval($params[1]); $image->effects()->gamma($gamma); } break; case 'colorize': // Syntax: colorize:couleur. Exemple: colorize:#ff00cc if (isset($params[1])) { $the_color = $palette->color($params[1]); $image->effects()->colorize($the_color); } break; } } $quality = $event->getQuality(); if (is_null($quality)) { $quality = ConfigQuery::read('default_images_quality_percent', 75); } // Allow image post-processing (watermarging, or other stuff...) $event->setImageObject($image); $dispatcher->dispatch(TheliaEvents::IMAGE_POSTPROCESSING, $event); $image = $event->getImageObject(); $image->save($cacheFilePath, array('quality' => $quality)); } else { throw new ImageException(sprintf("Source file %s cannot be opened.", basename($source_file))); } } } // Compute the image URL $processed_image_url = $this->getCacheFileURL($subdir, basename($cacheFilePath)); // compute the full resolution image path in cache $original_image_url = $this->getCacheFileURL($subdir, basename($originalImagePathInCache)); // Update the event with file path and file URL $event->setCacheFilepath($cacheFilePath); $event->setCacheOriginalFilepath($originalImagePathInCache); $event->setFileUrl(URL::getInstance()->absoluteUrl($processed_image_url, null, URL::PATH_TO_FILE)); $event->setOriginalFileUrl(URL::getInstance()->absoluteUrl($original_image_url, null, URL::PATH_TO_FILE)); }