diff options
Diffstat (limited to 'apps/theming/lib')
-rw-r--r-- | apps/theming/lib/Controller/IconController.php | 117 | ||||
-rw-r--r-- | apps/theming/lib/IconBuilder.php | 140 | ||||
-rw-r--r-- | apps/theming/lib/ThemingDefaults.php | 17 |
3 files changed, 190 insertions, 84 deletions
diff --git a/apps/theming/lib/Controller/IconController.php b/apps/theming/lib/Controller/IconController.php index 5770bd20742..78d41d621a0 100644 --- a/apps/theming/lib/Controller/IconController.php +++ b/apps/theming/lib/Controller/IconController.php @@ -22,6 +22,7 @@ */ namespace OCA\Theming\Controller; +use OCA\Theming\IconBuilder; use OCA\Theming\Template; use OCA\Theming\ThemingDefaults; use OCP\AppFramework\Controller; @@ -35,9 +36,6 @@ use OCP\IConfig; use OCP\IL10N; use OCP\IRequest; use OCA\Theming\Util; -use OCP\IURLGenerator; -use Imagick; -use ImagickPixel; class IconController extends Controller { /** @var ThemingDefaults */ @@ -52,7 +50,8 @@ class IconController extends Controller { private $config; /** @var IRootFolder */ private $rootFolder; - + /** @var IconBuilder */ + private $iconBuilder; /** * IconController constructor. @@ -84,6 +83,9 @@ class IconController extends Controller { $this->l = $l; $this->config = $config; $this->rootFolder = $rootFolder; + if(extension_loaded('imagick')) { + $this->iconBuilder = new IconBuilder($this->themingDefaults, $this->util); + } } /** @@ -91,7 +93,7 @@ class IconController extends Controller { * @NoCSRFRequired * * @param $app app name - * @param $image image file name + * @param $image image file name (svg required) * @return StreamResponse|DataResponse */ public function getThemedIcon($app, $image) { @@ -99,10 +101,10 @@ class IconController extends Controller { $svg = file_get_contents($image); $color = $this->util->elementColor($this->themingDefaults->getMailHeaderColor()); $svg = $this->util->colorizeSvg($svg, $color); - $response = new DataDisplayResponse($svg, Http::STATUS_OK, ['Content-Type' => 'image/svg+xml']); $response->cacheFor(86400); $response->addHeader('Expires', date(\DateTime::RFC2822, $this->timeFactory->getTime())); + $response->addHeader('Pragma', 'cache'); return $response; } @@ -116,14 +118,21 @@ class IconController extends Controller { * @return StreamResponse|DataResponse */ public function getFavicon($app="core") { - $icon = $this->renderAppIcon($app); - $icon->resizeImage(32, 32, Imagick::FILTER_LANCZOS, 1); - $icon->setImageFormat("png24"); + if($this->themingDefaults->shouldReplaceIcons()) { + $icon = $this->iconBuilder->getFavicon($app); + $response = new DataDisplayResponse($icon, Http::STATUS_OK, ['Content-Type' => 'image/x-icon']); + $response->cacheFor(86400); + $response->addHeader('Expires', date(\DateTime::RFC2822, $this->timeFactory->getTime())); + $response->addHeader('Pragma', 'cache'); + return $response; + } else { + $response = new DataDisplayResponse(null, Http::STATUS_NOT_FOUND); + $response->cacheFor(86400); + $response->addHeader('Expires', date(\DateTime::RFC2822, $this->timeFactory->getTime())); + return $response; + } + - $response = new DataDisplayResponse($icon, Http::STATUS_OK, ['Content-Type' => 'image/x-icon']); - $response->cacheFor(86400); - $response->addHeader('Expires', date(\DateTime::RFC2822, $this->timeFactory->getTime())); - return $response; } /** @@ -136,80 +145,20 @@ class IconController extends Controller { * @return StreamResponse|DataResponse */ public function getTouchIcon($app="core") { - $icon = $this->renderAppIcon($app); - $icon->setImageFormat("png24"); - - $response = new DataDisplayResponse($icon, Http::STATUS_OK, ['Content-Type' => 'image/png']); - $response->cacheFor(86400); - $response->addHeader('Expires', date(\DateTime::RFC2822, $this->timeFactory->getTime())); - return $response; - } - - /** - * Render app icon on themed background color - * fallback to logo - * - * @param $app app name - * @return Imagick - */ - private function renderAppIcon($app) { - $appIcon = $this->util->getAppIcon($app); - $color = $this->themingDefaults->getMailHeaderColor(); - $mime = mime_content_type($appIcon); - // generate background image with rounded corners - $background = '<?xml version="1.0" encoding="UTF-8"?>' . - '<svg xmlns="http://www.w3.org/2000/svg" version="1.1" xmlns:cc="http://creativecommons.org/ns#" width="512" height="512" xmlns:xlink="http://www.w3.org/1999/xlink">' . - '<rect x="0" y="0" rx="75" ry="75" width="512" height="512" style="fill:' . $color . ';" />' . - '</svg>'; - - // resize svg magic as this seems broken in Imagemagick - if($mime === "image/svg+xml") { - $svg = file_get_contents($appIcon); - - $tmp = new Imagick(); - $tmp->readImageBlob($svg); - $x = $tmp->getImageWidth(); - $y = $tmp->getImageHeight(); - $res = $tmp->getImageResolution(); - $tmp->destroy(); - - // convert svg to resized image - $appIconFile = new Imagick(); - $resX = (int)(512 * $res['x'] / $x * 2.53); - $resY = (int)(512 * $res['y'] / $y * 2.53); - $appIconFile->setResolution($resX, $resY); - $appIconFile->setBackgroundColor(new ImagickPixel('transparent')); - $appIconFile->readImageBlob($svg); + if($this->themingDefaults->shouldReplaceIcons()) { + $icon = $this->iconBuilder->getTouchIcon($app); + $response = new DataDisplayResponse($icon, Http::STATUS_OK, ['Content-Type' => 'image/png']); + $response->cacheFor(86400); + $response->addHeader('Expires', date(\DateTime::RFC2822, $this->timeFactory->getTime())); + $response->addHeader('Pragma', 'cache'); + return $response; } else { - $appIconFile = new Imagick(); - $appIconFile->setBackgroundColor(new ImagickPixel('transparent')); - $appIconFile->readImageBlob(file_get_contents($appIcon)); - $appIconFile->scaleImage(512, 512, true); + $response = new DataDisplayResponse(null, Http::STATUS_NOT_FOUND); + $response->cacheFor(86400); + $response->addHeader('Expires', date(\DateTime::RFC2822, $this->timeFactory->getTime())); + return $response; } - - // offset for icon positioning - $border_w = (int)($appIconFile->getImageWidth() * 0.05); - $border_h = (int)($appIconFile->getImageHeight() * 0.05); - $innerWidth = (int)($appIconFile->getImageWidth() - $border_w * 2); - $innerHeight = (int)($appIconFile->getImageHeight() - $border_h * 2); - $appIconFile->adaptiveResizeImage($innerWidth, $innerHeight); - // center icon - $offset_w = 512 / 2 - $innerWidth / 2; - $offset_h = 512 / 2 - $innerHeight / 2; - - $appIconFile->setImageFormat("png24"); - - $finalIconFile = new Imagick(); - $finalIconFile->readImageBlob($background); - $finalIconFile->setImageVirtualPixelMethod(Imagick::VIRTUALPIXELMETHOD_TRANSPARENT); - $finalIconFile->setImageArtifact('compose:args', "1,0,-0.5,0.5"); - $finalIconFile->compositeImage($appIconFile, Imagick::COMPOSITE_ATOP, $offset_w, $offset_h); - $finalIconFile->resizeImage(512, 512, Imagick::FILTER_LANCZOS, 1); - - $appIconFile->destroy(); - return $finalIconFile; } - }
\ No newline at end of file diff --git a/apps/theming/lib/IconBuilder.php b/apps/theming/lib/IconBuilder.php new file mode 100644 index 00000000000..b61e12d9236 --- /dev/null +++ b/apps/theming/lib/IconBuilder.php @@ -0,0 +1,140 @@ +<?php +/** + * @copyright Copyright (c) 2016 Julius Härtl <jus@bitgrid.net> + * + * @author Julius Härtl <jus@bitgrid.net> + * + * @license GNU AGPL version 3 or any later version + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + */ + +namespace OCA\Theming; + +use Imagick; +use ImagickPixel; + +class IconBuilder { + /** @var ThemingDefaults */ + private $themingDefaults; + /** @var Util */ + private $util; + + /** + * IconBuilder constructor. + * + * @param ThemingDefaults $themingDefaults + * @param Util $util + */ + public function __construct( + ThemingDefaults $themingDefaults, + Util $util + ) { + $this->themingDefaults = $themingDefaults; + $this->util = $util; + } + + /** + * @param $app app name + * @return string image blob + */ + public function getFavicon($app) { + $icon = $this->renderAppIcon($app); + $icon->resizeImage(32, 32, Imagick::FILTER_LANCZOS, 1); + $icon->setImageFormat("png24"); + $data = $icon->getImageBlob(); + $icon->destroy(); + return $data; + } + + /** + * @param $app app name + * @return string image blob + */ + public function getTouchIcon($app) { + $icon = $this->renderAppIcon($app); + $icon->setImageFormat("png24"); + $data = $icon->getImageBlob(); + $icon->destroy(); + return $data; + } + + /** + * Render app icon on themed background color + * fallback to logo + * + * @param $app app name + * @return Imagick + */ + public function renderAppIcon($app) { + $appIcon = $this->util->getAppIcon($app); + + $color = $this->themingDefaults->getMailHeaderColor(); + $mime = mime_content_type($appIcon); + // generate background image with rounded corners + $background = '<?xml version="1.0" encoding="UTF-8"?>' . + '<svg xmlns="http://www.w3.org/2000/svg" version="1.1" xmlns:cc="http://creativecommons.org/ns#" width="512" height="512" xmlns:xlink="http://www.w3.org/1999/xlink">' . + '<rect x="0" y="0" rx="75" ry="75" width="512" height="512" style="fill:' . $color . ';" />' . + '</svg>'; + + // resize svg magic as this seems broken in Imagemagick + if($mime === "image/svg+xml") { + $svg = file_get_contents($appIcon); + + $tmp = new Imagick(); + $tmp->readImageBlob($svg); + $x = $tmp->getImageWidth(); + $y = $tmp->getImageHeight(); + $res = $tmp->getImageResolution(); + $tmp->destroy(); + + // convert svg to resized image + $appIconFile = new Imagick(); + $resX = (int)(512 * $res['x'] / $x * 2.53); + $resY = (int)(512 * $res['y'] / $y * 2.53); + $appIconFile->setResolution($resX, $resY); + $appIconFile->setBackgroundColor(new ImagickPixel('transparent')); + $appIconFile->readImageBlob($svg); + } else { + $appIconFile = new Imagick(); + $appIconFile->setBackgroundColor(new ImagickPixel('transparent')); + $appIconFile->readImageBlob(file_get_contents($appIcon)); + $appIconFile->scaleImage(512, 512, true); + } + + // offset for icon positioning + $border_w = (int)($appIconFile->getImageWidth() * 0.05); + $border_h = (int)($appIconFile->getImageHeight() * 0.05); + $innerWidth = (int)($appIconFile->getImageWidth() - $border_w * 2); + $innerHeight = (int)($appIconFile->getImageHeight() - $border_h * 2); + $appIconFile->adaptiveResizeImage($innerWidth, $innerHeight); + // center icon + $offset_w = 512 / 2 - $innerWidth / 2; + $offset_h = 512 / 2 - $innerHeight / 2; + + $appIconFile->setImageFormat("png24"); + + $finalIconFile = new Imagick(); + $finalIconFile->readImageBlob($background); + $finalIconFile->setImageVirtualPixelMethod(Imagick::VIRTUALPIXELMETHOD_TRANSPARENT); + $finalIconFile->setImageArtifact('compose:args', "1,0,-0.5,0.5"); + $finalIconFile->compositeImage($appIconFile, Imagick::COMPOSITE_ATOP, $offset_w, $offset_h); + $finalIconFile->resizeImage(512, 512, Imagick::FILTER_LANCZOS, 1); + + $appIconFile->destroy(); + return $finalIconFile; + } + +}
\ No newline at end of file diff --git a/apps/theming/lib/ThemingDefaults.php b/apps/theming/lib/ThemingDefaults.php index 9139dd56247..b7968d0073f 100644 --- a/apps/theming/lib/ThemingDefaults.php +++ b/apps/theming/lib/ThemingDefaults.php @@ -145,6 +145,23 @@ class ThemingDefaults extends \OC_Defaults { } /** + * Check if Imagemagick is enabled and if SVG is supported + * otherwise we can't render custom icons + * + * @return bool + */ + public function shouldReplaceIcons() { + if(extension_loaded('imagick')) { + $checkImagick = new \Imagick(); + if (count($checkImagick->queryFormats('SVG')) >= 1) { + return true; + } + $checkImagick->clear(); + } + return false; + } + + /** * Increases the cache buster key */ private function increaseCacheBuster() { |