public function redimlive($type, $id, $offset, $width, $height, $resizeMode = 'none') { $object = ucfirst($type); $queryClass = sprintf("Thelia\\Model\\%sImageQuery", $object); $filterMethod = sprintf("filterBy%sId", $object); // xxxImageQuery::create() $method = new \ReflectionMethod($queryClass, 'create'); /** @var ModelCriteria $search */ $search = $method->invoke(null); // Static ! // $query->filterByXXX(id) $method = new \ReflectionMethod($queryClass, $filterMethod); $method->invoke($search, $id); $search->orderByPosition(Criteria::ASC)->offset(max(0, $offset - 1))->limit(1); if (null !== ($image = $search->findOne())) { switch ($resizeMode) { case 'crop': $resizeMode = \Thelia\Action\Image::EXACT_RATIO_WITH_CROP; break; case 'borders': $resizeMode = \Thelia\Action\Image::EXACT_RATIO_WITH_BORDERS; break; case 'none': default: $resizeMode = \Thelia\Action\Image::KEEP_IMAGE_RATIO; } $baseSourceFilePath = ConfigQuery::read('images_library_path'); if ($baseSourceFilePath === null) { $baseSourceFilePath = THELIA_LOCAL_DIR . 'media' . DS . 'images'; } else { $baseSourceFilePath = THELIA_ROOT . $baseSourceFilePath; } // Put source image file path $sourceFilePath = sprintf('%s/%s/%s', $baseSourceFilePath, $object, $image->getFile()); // Create image processing event $event = new ImageEvent($this->getRequest()); $event->setSourceFilepath($sourceFilePath)->setCacheSubdirectory($object)->setWidth($width)->setHeight($height)->setResizeMode($resizeMode); try { // Dispatch image processing event $this->getDispatcher()->dispatch(TheliaEvents::IMAGE_PROCESS, $event); return Response::create(file_get_contents($event->getCacheFilepath()), 200, array('Content-type' => image_type_to_mime_type(exif_imagetype($event->getCacheFilepath())))); } catch (\Exception $ex) { Tlog::getInstance()->addError(sprintf("Failed to process image: %s", $ex->getMessage())); return new Response("", 500); } } else { $this->pageNotFound(); } }
protected function execute(InputInterface $input, OutputInterface $output) { $request = new Request(); try { $event = new ImageEvent($request); $subdir = $input->getArgument('subdir'); if (!is_null($subdir)) { $event->setCacheSubdirectory($subdir); } $this->getDispatcher()->dispatch(TheliaEvents::IMAGE_CLEAR_CACHE, $event); $output->writeln(sprintf('%s image cache successfully cleared.', is_null($subdir) ? 'Entire' : ucfirst($subdir))); } catch (\Exception $ex) { $output->writeln(sprintf("Failed to clear image cache: %s", $ex->getMessage())); } }
public function addWatermark(ImageEvent $event) { $image = $event->getImageObject(); $size = $image->getSize(); Tlog::getInstance()->debug("Category: " . $event->getCacheSubdirectory()); if ($event->getCacheSubdirectory() == 'product' && $size->getHeight() > 200) { $imagine = $this->createImagineInstance(); $watermark = $imagine->open(__DIR__ . DS . '..' . DS . '/Config/watermark.png'); $watermark->resize($watermark->getSize()->heighten(round(0.1 * $size->getHeight()))); $wSize = $watermark->getSize(); $delta = round(0.02 * $size->getHeight()); $bottomRight = new Point($size->getWidth() - $wSize->getWidth() - $delta, $size->getHeight() - $wSize->getHeight() - $delta); $image->paste($watermark, $bottomRight); } }
/** * @param LoopResult $loopResult * * @return LoopResult */ public function parseResults(LoopResult $loopResult) { /** @var \Carousel\Model\Carousel $carousel */ foreach ($loopResult->getResultDataCollection() as $carousel) { $loopResultRow = new LoopResultRow($carousel); $event = new ImageEvent(); $event->setSourceFilepath($carousel->getUploadDir() . DS . $carousel->getFile())->setCacheSubdirectory('carousel'); switch ($this->getResizeMode()) { case 'crop': $resize_mode = \Thelia\Action\Image::EXACT_RATIO_WITH_CROP; break; case 'borders': $resize_mode = \Thelia\Action\Image::EXACT_RATIO_WITH_BORDERS; break; case 'none': default: $resize_mode = \Thelia\Action\Image::KEEP_IMAGE_RATIO; } // Prepare tranformations $width = $this->getWidth(); $height = $this->getHeight(); $rotation = $this->getRotation(); $background_color = $this->getBackgroundColor(); $quality = $this->getQuality(); $effects = $this->getEffects(); if (!is_null($width)) { $event->setWidth($width); } if (!is_null($height)) { $event->setHeight($height); } $event->setResizeMode($resize_mode); if (!is_null($rotation)) { $event->setRotation($rotation); } if (!is_null($background_color)) { $event->setBackgroundColor($background_color); } if (!is_null($quality)) { $event->setQuality($quality); } if (!is_null($effects)) { $event->setEffects($effects); } $event->setAllowZoom($this->getAllowZoom()); // Dispatch image processing event $this->dispatcher->dispatch(TheliaEvents::IMAGE_PROCESS, $event); $loopResultRow->set('ID', $carousel->getId())->set("LOCALE", $this->locale)->set("IMAGE_URL", $event->getFileUrl())->set("ORIGINAL_IMAGE_URL", $event->getOriginalFileUrl())->set("IMAGE_PATH", $event->getCacheFilepath())->set("ORIGINAL_IMAGE_PATH", $event->getSourceFilepath())->set("TITLE", $carousel->getVirtualColumn('i18n_TITLE'))->set("CHAPO", $carousel->getVirtualColumn('i18n_CHAPO'))->set("DESCRIPTION", $carousel->getVirtualColumn('i18n_DESCRIPTION'))->set("POSTSCRIPTUM", $carousel->getVirtualColumn('i18n_POSTSCRIPTUM'))->set("ALT", $carousel->getVirtualColumn('i18n_ALT'))->set("URL", $carousel->getUrl())->set('POSITION', $carousel->getPosition()); $loopResult->addRow($loopResultRow); } return $loopResult; }
/** * 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)); }
/** * @param ProductImage $image * @return ImageEvent */ public function createProductImageEvent(ProductImage $image) { $imageEvent = new ImageEvent($this->request); $baseSourceFilePath = ConfigQuery::read('images_library_path'); if ($baseSourceFilePath === null) { $baseSourceFilePath = THELIA_LOCAL_DIR . 'media' . DS . 'images'; } else { $baseSourceFilePath = THELIA_ROOT . $baseSourceFilePath; } // Put source image file path $sourceFilePath = sprintf('%s/%s/%s', $baseSourceFilePath, 'product', $image->getFile()); $imageEvent->setSourceFilepath($sourceFilePath); $imageEvent->setCacheSubdirectory('product'); return $imageEvent; }
/** * Try to clear directory ouside of the cache * * @expectedException \InvalidArgumentException */ public function testClearUnallowedPathCache() { $event = new ImageEvent($this->request); $event->setDispatcher($this->getDispatcher()); $event->setCacheSubdirectory('../../../..'); $image = new Image($this->getFileManager()); $image->clearCache($event); }
public function parseResults(LoopResult $loopResult) { // Create image processing event $event = new ImageEvent($this->request); // Prepare tranformations $width = $this->getWidth(); $height = $this->getHeight(); $rotation = $this->getRotation(); $background_color = $this->getBackgroundColor(); $quality = $this->getQuality(); $effects = $this->getEffects(); if (!is_null($effects)) { $effects = explode(',', $effects); } switch ($this->getResizeMode()) { case 'crop': $resize_mode = \Thelia\Action\Image::EXACT_RATIO_WITH_CROP; break; case 'borders': $resize_mode = \Thelia\Action\Image::EXACT_RATIO_WITH_BORDERS; break; case 'none': default: $resize_mode = \Thelia\Action\Image::KEEP_IMAGE_RATIO; } foreach ($loopResult->getResultDataCollection() as $result) { // Setup required transformations if (!is_null($width)) { $event->setWidth($width); } if (!is_null($height)) { $event->setHeight($height); } $event->setResizeMode($resize_mode); if (!is_null($rotation)) { $event->setRotation($rotation); } if (!is_null($background_color)) { $event->setBackgroundColor($background_color); } if (!is_null($quality)) { $event->setQuality($quality); } if (!is_null($effects)) { $event->setEffects($effects); } // Put source image file path $source_filepath = sprintf("%s%s/%s/%s", THELIA_ROOT, ConfigQuery::read('images_library_path', 'local' . DS . 'media' . DS . 'images'), $this->objectType, $result->getFile()); $event->setSourceFilepath($source_filepath); $event->setCacheSubdirectory($this->objectType); $loopResultRow = new LoopResultRow($result); $loopResultRow->set("ID", $result->getId())->set("LOCALE", $this->locale)->set("ORIGINAL_IMAGE_PATH", $source_filepath)->set("TITLE", $result->getVirtualColumn('i18n_TITLE'))->set("CHAPO", $result->getVirtualColumn('i18n_CHAPO'))->set("DESCRIPTION", $result->getVirtualColumn('i18n_DESCRIPTION'))->set("POSTSCRIPTUM", $result->getVirtualColumn('i18n_POSTSCRIPTUM'))->set("VISIBLE", $result->getVisible())->set("POSITION", $result->getPosition())->set("OBJECT_TYPE", $this->objectType)->set("OBJECT_ID", $this->objectId); $addRow = true; $returnErroredImages = $this->getBackendContext() || !$this->getIgnoreProcessingErrors(); try { // Dispatch image processing event $this->dispatcher->dispatch(TheliaEvents::IMAGE_PROCESS, $event); $loopResultRow->set("IMAGE_URL", $event->getFileUrl())->set("ORIGINAL_IMAGE_URL", $event->getOriginalFileUrl())->set("IMAGE_PATH", $event->getCacheFilepath())->set("PROCESSING_ERROR", false); } catch (\Exception $ex) { // Ignore the result and log an error Tlog::getInstance()->addError(sprintf("Failed to process image in image loop: %s", $ex->getMessage())); if ($returnErroredImages) { $loopResultRow->set("IMAGE_URL", '')->set("ORIGINAL_IMAGE_URL", '')->set("IMAGE_PATH", '')->set("PROCESSING_ERROR", true); } else { $addRow = false; } } if ($addRow) { $this->addOutputFields($loopResultRow, $result); $loopResult->addRow($loopResultRow); } } return $loopResult; }
/** * @param $type * @param RewritingUrl $result * @param $configValues * @param $sitemap */ protected function generateSitemapImage($type, $result, $configValues, &$sitemap) { $event = new ImageEvent(); $event->setWidth($configValues['width'])->setHeight($configValues['height'])->setQuality($configValues['quality'])->setRotation($configValues['rotation'])->setResizeMode($configValues['resizeMode'])->setBackgroundColor($configValues['bgColor'])->setAllowZoom($configValues['allowZoom']); // Put source image file path $source_filepath = sprintf("%s%s/%s/%s", THELIA_ROOT, ConfigQuery::read('images_library_path', 'local/media/images'), $type, $result->getVirtualColumn('PRODUCT_FILE')); $event->setSourceFilepath($source_filepath); $event->setCacheSubdirectory($type); try { // Dispatch image processing event $this->dispatch(TheliaEvents::IMAGE_PROCESS, $event); // New sitemap image entry $sitemap[] = ' <url> <loc>' . URL::getInstance()->absoluteUrl($result->getUrl()) . '</loc> <image:image> <image:loc>' . $event->getFileUrl() . '</image:loc> <image:title>' . htmlspecialchars($result->getVirtualColumn('PRODUCT_TITLE')) . '</image:title> </image:image> </url>'; } catch (\Exception $ex) { } }