/** * Get the average pixel colour from the given file using Image Magick * * @param string $filename * @param bool $as_hex Set to true, the function will return the 6 character HEX value of the colour. * If false, an array will be returned with r, g, b components. */ function get_average_colour($filename, $as_hex_string = true) { try { // Read image file with Image Magick $image = new Imagick($filename); $image->setImageColorspace(2); // Scale down to 1x1 pixel to make Imagick do the average $image->scaleimage(1, 1); /** @var ImagickPixel $pixel */ if (!($pixels = $image->getimagehistogram())) { return null; } } catch (ImagickException $e) { // Image Magick Error! return null; } catch (Exception $e) { // Unknown Error! return null; } $pixel = reset($pixels); $rgb = $pixel->getcolor(); if ($as_hex_string) { return sprintf('%02X%02X%02X', $rgb['r'], $rgb['g'], $rgb['b']); } return $rgb; }
/** * this is to force RGB and to apply custom icc color profiles */ protected function applyColorProfiles() { if ($this->resource->getImageColorspace() == Imagick::COLORSPACE_CMYK) { if (self::getCMYKColorProfile() && self::getRGBColorProfile()) { $profiles = $this->resource->getImageProfiles('*', false); // we're only interested if ICC profile(s) exist $has_icc_profile = array_search('icc', $profiles) !== false; // if it doesn't have a CMYK ICC profile, we add one if ($has_icc_profile === false) { $this->resource->profileImage('icc', self::getCMYKColorProfile()); } // then we add an RGB profile $this->resource->profileImage('icc', self::getRGBColorProfile()); $this->resource->setImageColorspace(Imagick::COLORSPACE_RGB); } } // this is a HACK to force grayscale images to be real RGB - truecolor, this is important if you want to use // thumbnails in PDF's because they do not support "real" grayscale JPEGs or PNGs // problem is described here: http://imagemagick.org/Usage/basics/#type // and here: http://www.imagemagick.org/discourse-server/viewtopic.php?f=2&t=6888#p31891 if ($this->resource->getimagetype() == Imagick::IMGTYPE_GRAYSCALE) { $draw = new ImagickDraw(); $draw->setFillColor("red"); $draw->setfillopacity(0.001); $draw->point(0, 0); $this->resource->drawImage($draw); } }
/** * @return $this */ public function setColorspaceToRGB() { $imageColorspace = $this->resource->getImageColorspace(); if ($imageColorspace == \Imagick::COLORSPACE_CMYK) { if (self::getCMYKColorProfile() && self::getRGBColorProfile()) { $profiles = $this->resource->getImageProfiles('*', false); // we're only interested if ICC profile(s) exist $has_icc_profile = array_search('icc', $profiles) !== false; // if it doesn't have a CMYK ICC profile, we add one if ($has_icc_profile === false) { $this->resource->profileImage('icc', self::getCMYKColorProfile()); } // then we add an RGB profile $this->resource->profileImage('icc', self::getRGBColorProfile()); $this->resource->setImageColorspace(\Imagick::COLORSPACE_SRGB); // we have to use SRGB here, no clue why but it works } else { $this->resource->setImageColorspace(\Imagick::COLORSPACE_SRGB); } } else { if ($imageColorspace == \Imagick::COLORSPACE_GRAY) { $this->resource->setImageColorspace(\Imagick::COLORSPACE_SRGB); } else { if (!in_array($imageColorspace, array(\Imagick::COLORSPACE_RGB, \Imagick::COLORSPACE_SRGB))) { $this->resource->setImageColorspace(\Imagick::COLORSPACE_SRGB); } else { // this is to handle embedded icc profiles in the RGB/sRGB colorspace $profiles = $this->resource->getImageProfiles('*', false); $has_icc_profile = array_search('icc', $profiles) !== false; if ($has_icc_profile) { try { // if getImageColorspace() says SRGB but the embedded icc profile is CMYK profileImage() will throw an exception $this->resource->profileImage('icc', self::getRGBColorProfile()); } catch (\Exception $e) { \Logger::warn($e); } } } } } // this is a HACK to force grayscale images to be real RGB - truecolor, this is important if you want to use // thumbnails in PDF's because they do not support "real" grayscale JPEGs or PNGs // problem is described here: http://imagemagick.org/Usage/basics/#type // and here: http://www.imagemagick.org/discourse-server/viewtopic.php?f=2&t=6888#p31891 $currentLocale = setlocale(LC_ALL, "0"); // this locale hack thing is also a hack for imagick setlocale(LC_ALL, ""); // details see https://www.pimcore.org/issues/browse/PIMCORE-2728 $draw = new \ImagickDraw(); $draw->setFillColor("#ff0000"); $draw->setfillopacity(0.01); $draw->point(floor($this->getWidth() / 2), floor($this->getHeight() / 2)); // place it in the middle of the image $this->resource->drawImage($draw); setlocale(LC_ALL, $currentLocale); // see setlocale() above, for details ;-) return $this; }
/** * Creates new image instance * * @param integer $width * @param integer $height * @param string $background * @return Intervention\Image\Image */ public function newImage($width, $height, $background = null) { $background = new Color($background); // create empty core $core = new \Imagick(); $core->newImage($width, $height, $background->getPixel(), 'png'); $core->setType(\Imagick::IMGTYPE_UNDEFINED); $core->setImagetype(\Imagick::IMGTYPE_UNDEFINED); $core->setColorspace(\Imagick::COLORSPACE_UNDEFINED); $core->setImageColorspace(\Imagick::COLORSPACE_UNDEFINED); // build image $image = new \Intervention\Image\Image(new self(), $core); return $image; }
/** * @return $this */ public function setColorspaceToRGB() { $imageColorspace = $this->resource->getImageColorspace(); if ($imageColorspace == \Imagick::COLORSPACE_CMYK) { if (self::getCMYKColorProfile() && self::getRGBColorProfile()) { $profiles = $this->resource->getImageProfiles('*', false); // we're only interested if ICC profile(s) exist $has_icc_profile = array_search('icc', $profiles) !== false; // if it doesn't have a CMYK ICC profile, we add one if ($has_icc_profile === false) { $this->resource->profileImage('icc', self::getCMYKColorProfile()); } // then we add an RGB profile $this->resource->profileImage('icc', self::getRGBColorProfile()); $this->resource->setImageColorspace(\Imagick::COLORSPACE_SRGB); // we have to use SRGB here, no clue why but it works } else { $this->resource->setImageColorspace(\Imagick::COLORSPACE_SRGB); } } else { if ($imageColorspace == \Imagick::COLORSPACE_GRAY) { $this->resource->setImageColorspace(\Imagick::COLORSPACE_SRGB); } else { if (!in_array($imageColorspace, array(\Imagick::COLORSPACE_RGB, \Imagick::COLORSPACE_SRGB))) { $this->resource->setImageColorspace(\Imagick::COLORSPACE_SRGB); } else { // this is to handle embedded icc profiles in the RGB/sRGB colorspace $profiles = $this->resource->getImageProfiles('*', false); $has_icc_profile = array_search('icc', $profiles) !== false; if ($has_icc_profile) { $this->resource->profileImage('icc', self::getRGBColorProfile()); } } } } // this is a HACK to force grayscale images to be real RGB - truecolor, this is important if you want to use // thumbnails in PDF's because they do not support "real" grayscale JPEGs or PNGs // problem is described here: http://imagemagick.org/Usage/basics/#type // and here: http://www.imagemagick.org/discourse-server/viewtopic.php?f=2&t=6888#p31891 $draw = new \ImagickDraw(); $draw->setFillColor("#ff0000"); $draw->setfillopacity(0.01); $draw->point(floor($this->getWidth() / 2), floor($this->getHeight() / 2)); // place it in the middle of the image $this->resource->drawImage($draw); return $this; }
function encode_imagick($ps_filepath, $ps_output_path, $pa_options) { if (!($magick = $this->mimetype2magick[$pa_options["output_mimetype"]])) { $this->error = "Invalid output format"; return false; } # # Open image # $h = new Imagick(); if (!$h->readImage($ps_filepath)) { $this->error = "Couldn't open image {$ps_filepath}"; return false; } if (function_exists('exif_read_data')) { if (is_array($va_exif = @exif_read_data($ps_filepath, 'EXIF', true, false))) { if (isset($va_exif['IFD0']['Orientation'])) { $vn_orientation = $va_exif['IFD0']['Orientation']; switch ($vn_orientation) { case 3: $h->rotateImage("#FFFFFF", 180); break; case 6: $h->rotateImage("#FFFFFF", 90); break; case 8: $h->rotateImage("#FFFFFF", -90); break; } } } } $h->setImageType(imagick::IMGTYPE_TRUECOLOR); if (!$h->setImageColorspace(imagick::COLORSPACE_RGB)) { $this->error = "Error during RGB colorspace transformation operation"; return false; } $va_tmp = $h->getImageGeometry(); $image_width = $va_tmp['width']; $image_height = $va_tmp['height']; if ($image_width < 10 || $image_height < 10) { $this->error = "Image is too small to be output as Tilepic; minimum dimensions are 10x10 pixels"; return false; } if ($pa_options["scale_factor"] != 1) { $image_width *= $pa_options["scale_factor"]; $image_height *= $pa_options["scale_factor"]; if (!$h->resizeImage($image_width, $image_height, imagick::FILTER_CUBIC, $pa_options["antialiasing"])) { $this->error = "Couldn't scale image"; return false; } } # # How many layers to make? # if (!$pa_options["layers"]) { $sw = $image_width * $pa_options["layer_ratio"]; $sh = $image_height * $pa_options["layer_ratio"]; $pa_options["layers"] = 1; while ($sw >= $pa_options["tile_width"] || $sh >= $pa_options["tile_height"]) { $sw = ceil($sw / $pa_options["layer_ratio"]); $sh = ceil($sh / $pa_options["layer_ratio"]); $pa_options["layers"]++; } } # # Cut image into tiles # $tiles = 0; $layer_list = array(); $base_width = $image_width; $base_height = $image_height; if ($this->debug) { print "BASE {$base_width} x {$base_height} \n"; } for ($l = $pa_options["layers"]; $l >= 1; $l--) { $x = $y = 0; $wx = $pa_options["tile_width"]; $wy = $pa_options["tile_height"]; if ($this->debug) { print "LAYER={$l}\n"; } if ($l < $pa_options["layers"]) { $image_width = ceil($image_width / $pa_options["layer_ratio"]); $image_height = ceil($image_height / $pa_options["layer_ratio"]); if ($this->debug) { print "RESIZE layer {$l} TO {$image_width} x {$image_height} \n"; } if (!$h->resizeImage($image_width, $image_height, imagick::FILTER_CUBIC, $pa_options["antialiasing"])) { $this->error = "Couldn't scale image"; return false; } } $i = 0; $layer_list[] = array(); while ($y < $image_height) { if (!($slice = $h->getImageRegion($wx, $wy, $x, $y))) { $this->error = "Couldn't create tile"; return false; } $slice->setCompressionQuality($pa_options["quality"]); if (!$slice->setImageFormat($magick)) { $reason = WandGetExceptionType($slice); $description = WandGetExceptionDescription($slice); $this->error = "Tile conversion failed: {$reason}; {$description}"; return false; } # --- remove color profile (saves lots of space) //$slice->removeImageProfile($slice); $layer_list[sizeof($layer_list) - 1][] = $slice->getImageBlob(); $slice->destroy(); $x += $pa_options["tile_width"]; if ($x >= $image_width) { $y += $pa_options["tile_height"]; $x = 0; } $i++; $tiles++; } if ($this->debug) { print "OUTPUT {$tiles} TILES FOR LAYER {$l} : {$image_width} x {$image_height}\n"; } } $h->destroy(); # # Write Tilepic format file # if ($this->debug) { print "WRITING FILE..."; } if ($fh = fopen($ps_output_path . ".tpc", "w")) { # --- attribute list $attribute_list = ""; $attributes = 0; if (isset($pa_options["attributes"]) && is_array($pa_options["attributes"])) { $pa_options["attributes"]["mimeType"] = $pa_options["output_mimetype"]; } else { $pa_options["attributes"] = array("mimeType" => $pa_options["output_mimetype"]); } foreach ($pa_options["attributes"] as $k => $v) { $attribute_list .= "{$k}={$v}"; $attributes++; } if ($this->debug) { print "header OK;"; } # --- header if (!fwrite($fh, "TPC\n")) { $this->error = "Could not write Tilepic signature"; return false; } if (!fwrite($fh, pack("NNNNNNnnNN", 40, $base_width, $base_height, $pa_options["tile_width"], $pa_options["tile_height"], $tiles, $pa_options["layers"], $pa_options["layer_ratio"], strlen($attribute_list), $attributes))) { $this->error = "Could not write Tilepic header"; return false; } # --- offset table $offset = 44 + $tiles * 4; for ($i = sizeof($layer_list) - 1; $i >= 0; $i--) { for ($j = 0; $j < sizeof($layer_list[$i]); $j++) { if (!fwrite($fh, pack("N", $offset))) { $this->error = "Could not write Tilepic offset table"; return false; } $offset += strlen($layer_list[$i][$j]); } } if ($this->debug) { print "offset table OK;"; } if (!fwrite($fh, pack("N", $offset))) { $this->error = "Could not finish writing Tilepic offset table"; return false; } # --- tiles for ($i = sizeof($layer_list) - 1; $i >= 0; $i--) { for ($j = 0; $j < sizeof($layer_list[$i]); $j++) { if (!fwrite($fh, $layer_list[$i][$j])) { $this->error = "Could not write Tilepic tile data"; return false; } } } if ($this->debug) { print "tiles OK;"; } unset($layer_list); # --- attributes if (!fwrite($fh, $attribute_list)) { $this->error = "Could not write Tilepic attributes"; return false; } if ($this->debug) { print "attributes OK\n"; } fclose($fh); return $pa_options; } else { $this->error = "Couldn't open output file {$ps_output_path}\n"; return false; } }
} else { Logger::debug('main', '(client/applications) No Session id nor public_webservices_access'); echo return_error(7, 'No Session id nor public_webservices_access'); die; } $applicationDB = ApplicationDB::getInstance(); $applications = $applicationDB->getApplicationsWithMimetype($_GET['id']); $apps = array(); foreach ($applications as $application) { if (!$application->haveIcon()) { continue; } $score = count($application->groups()); if ($application->getAttribute('type') == 'windows') { $score += 10; } $apps[$score] = $application; } header('Content-Type: image/png'); $first = new Imagick(realpath(dirname(__FILE__) . '/../admin/media/image/empty.png')); if (!is_array($apps) || count($apps) == 0) { echo $first; die; } arsort($apps); $application = array_shift($apps); $second = new Imagick(realpath($application->getIconPath())); $second->scaleImage(16, 16); $first->setImageColorspace($second->getImageColorspace()); $first->compositeImage($second, $second->getImageCompose(), 6, 10); echo $first;
function grayImage($imagePath) { $image = new Imagick(); $image->readImage('../uploads/' . $imagePath); $image->setImageColorspace(2); $image->writeImage('../uploads/' . $imagePath); }
<?php $target_dir = "/var/www/html/"; $target_file = $target_dir . basename($_FILES["file"]["name"]); // Check if image file is a actual image or fake image if (isset($_POST["submit"])) { $target_dir = "/var/www/html/"; $target_file = $target_dir . basename($_FILES["file"]["name"]); move_uploaded_file($_FILES["file"]["tmp_name"], $target_file); // Imagemagick stuff for exploiting // push graphic-context // viewbox 0 0 640 480 // fill 'url(https://voidsec1.com/logo.png"|touch "/tmp/passwd)' // pop graphic-context $im = new Imagick(realpath($target_file)); $im->setImageColorspace(255); $im->setCompression(Imagick::COMPRESSION_JPEG); $im->setCompressionQuality(60); $im->setImageFormat('jpeg'); echo "The file " . basename($_FILES["file"]["name"]) . " has been uploaded."; }
function Imagen__CrearMiniatura($Origen, $Destino, $Ancho = 100, $Alto = 100) { $im = new Imagick($Origen); $im->setImageColorspace(255); $im->setCompression(Imagick::COMPRESSION_JPEG); $im->setCompressionQuality(80); $im->setImageFormat('jpeg'); list($newX, $newY) = scaleImage($im->getImageWidth(), $im->getImageHeight(), $Ancho, $Alto); $im->thumbnailImage($newX, $newY, false); return $im->writeImage($Destino); }
/** * Convert image to a given type * * @param int $type Destination file type (see class constants) * @param string $filename Output filename (if empty, original file will be used * and filename extension will be modified) * * @return bool True on success, False on failure */ public function convert($type, $filename = null) { $rcube = rcube::get_instance(); $convert = $rcube->config->get('im_convert_path', false); if (!$filename) { $filename = $this->image_file; // modify extension if ($extension = self::$extensions[$type]) { $filename = preg_replace('/\\.[^.]+$/', '', $filename) . '.' . $extension; } } // use ImageMagick in command line if ($convert) { $p['in'] = $this->image_file; $p['out'] = $filename; $p['type'] = self::$extensions[$type]; $result = rcube::exec($convert . ' 2>&1 -colorspace sRGB -strip -quality 75 {in} {type}:{out}', $p); if ($result === '') { chmod($filename, 0600); return true; } } // use PHP's Imagick class if (class_exists('Imagick', false)) { try { $image = new Imagick($this->image_file); $image->setImageColorspace(Imagick::COLORSPACE_SRGB); $image->setImageCompressionQuality(75); $image->setImageFormat(self::$extensions[$type]); $image->stripImage(); if ($image->writeImage($filename)) { @chmod($filename, 0600); return true; } } catch (Exception $e) { rcube::raise_error($e, true, false); } } // use GD extension (TIFF isn't supported) $props = $this->props(); // do we have enough memory? (#1489937) if (strtoupper(substr(PHP_OS, 0, 3)) == 'WIN' && !$this->mem_check($props)) { return false; } if ($props['gd_type']) { if ($props['gd_type'] == IMAGETYPE_JPEG && function_exists('imagecreatefromjpeg')) { $image = imagecreatefromjpeg($this->image_file); } else { if ($props['gd_type'] == IMAGETYPE_GIF && function_exists('imagecreatefromgif')) { $image = imagecreatefromgif($this->image_file); } else { if ($props['gd_type'] == IMAGETYPE_PNG && function_exists('imagecreatefrompng')) { $image = imagecreatefrompng($this->image_file); } else { // @TODO: print error to the log? return false; } } } if ($type == self::TYPE_JPG) { $result = imagejpeg($image, $filename, 75); } else { if ($type == self::TYPE_GIF) { $result = imagegif($image, $filename); } else { if ($type == self::TYPE_PNG) { $result = imagepng($image, $filename, 6, PNG_ALL_FILTERS); } } } if ($result) { @chmod($filename, 0600); return true; } } // @TODO: print error to the log? return false; }
/** * [postRequestAtLocal 上传图片 扩展(待完善)] * @param array $img_info [图片上传信息] * @param [type] $rel_path [生成的路径 ] * @return [type] [description] */ public function postRequestAtLocal($img_info = array(), $rel_path = null) { if (empty($img_info) || !$rel_path) { return false; } $full_path = self::LOCAL_PATH . '/' . $rel_path; $rdir = dirname($full_path); if (!file_exists($rdir)) { $oldumask = umask(0); mkdir($rdir, 0777, TRUE); chmod($rdir, 0777); umask($oldumask); } // Step 3:图片处理 $compress = empty($_GET['compress']) || $_GET['cmopress'] != 'n' ? 'y' : $_GET['compress']; $im = new Imagick(); try { $im->readImageBlob(file_get_contents($img_info['tmp_name'])); } catch (Exception $e) { die($e->getMessage()); } // 获取图片格式 $image_format = strtoupper($im->getImageFormat()); switch ($image_format) { case 'PNG': $new_name = $full_path . self::DEFAULT_SUFFIX; $full_path .= ".png"; $im->setImageColorspace(Imagick::COLORSPACE_RGB); $im->setImageFormat("PNG") or die("Error:"); if ($compress != "n") { $im->setCompressionQuality(80) or die("Error:"); } $im->writeImage($full_path) or die("Error:"); rename($full_path, $new_name); $full_path = $new_name; $type = "image/png"; break; case 'GIF': $new_name = $full_path . self::DEFAULT_SUFFIX; $full_path .= ".gif"; $im->setImageColorspace(Imagick::COLORSPACE_RGB); $im->setImageFormat("GIF") or die("Error:"); if ($compress != "n") { $im->setCompressionQuality(80) or die("Error:"); } $im->writeImage($full_path, TRUE) or die("Error:"); rename($full_path, $new_name); $full_path = $new_name; $type = "image/gif"; break; default: $full_path .= self::DEFAULT_SUFFIX; $im->setImageColorspace(imagick::COLORSPACE_RGB); $im->setImageFormat("JPG") or die("Error:"); if ($compress != "n") { $im->setCompression(Imagick::COMPRESSION_JPEG) or die("Error:"); $im->setCompressionQuality(80) or die("Error:"); } $im->writeImage($full_path) or die("Error:"); $type = "image/jpeg"; break; } }
/** * Put image to square * * @param string $path image file * @param int $width square width * @param int $height square height * @param int|string $align reserved * @param int|string $valign reserved * @param string $bgcolor square background color in #rrggbb format * @param string $destformat image destination format * @param int $jpgQuality JEPG quality (1-100) * @return false|string * @author Dmitry (dio) Levashov * @author Alexey Sukhotin */ protected function imgSquareFit($path, $width, $height, $align = 'center', $valign = 'middle', $bgcolor = '#0000ff', $destformat = null, $jpgQuality = null) { if (($s = getimagesize($path)) == false) { return false; } $result = false; /* Coordinates for image over square aligning */ $y = ceil(abs($height - $s[1]) / 2); $x = ceil(abs($width - $s[0]) / 2); if (!$jpgQuality) { $jpgQuality = $this->options['jpgQuality']; } elFinder::extendTimeLimit(300); switch ($this->imgLib) { case 'imagick': try { $img = new imagick($path); } catch (Exception $e) { return false; } if ($bgcolor === 'transparent') { $bgcolor = 'rgba(255, 255, 255, 0.0)'; } $ani = $img->getNumberImages() > 1; if ($ani && is_null($destformat)) { $img1 = new Imagick(); $img1->setFormat('gif'); $img = $img->coalesceImages(); do { $gif = new Imagick(); $gif->newImage($width, $height, new ImagickPixel($bgcolor)); $gif->setImageColorspace($img->getImageColorspace()); $gif->setImageFormat('gif'); $gif->compositeImage($img, imagick::COMPOSITE_OVER, $x, $y); $gif->setImageDelay($img->getImageDelay()); $gif->setImageIterations($img->getImageIterations()); $img1->addImage($gif); $gif->clear(); } while ($img->nextImage()); $img1 = $img1->optimizeImageLayers(); $result = $img1->writeImages($path, true); } else { if ($ani) { $img->setFirstIterator(); } $img1 = new Imagick(); $img1->newImage($width, $height, new ImagickPixel($bgcolor)); $img1->setImageColorspace($img->getImageColorspace()); $img1->compositeImage($img, imagick::COMPOSITE_OVER, $x, $y); $result = $this->imagickImage($img1, $path, $destformat, $jpgQuality); } $img1->clear(); $img->clear(); return $result ? $path : false; break; case 'convert': extract($this->imageMagickConvertPrepare($path, $destformat, $jpgQuality, $s)); if ($bgcolor === 'transparent') { $bgcolor = 'rgba(255, 255, 255, 0.0)'; } $cmd = sprintf('convert -size %dx%d "xc:%s" png:- | convert%s%s png:- %s -geometry +%d+%d -compose over -composite%s %s', $width, $height, $bgcolor, $coalesce, $jpgQuality, $quotedPath, $x, $y, $deconstruct, $quotedDstPath); $result = false; if ($this->procExec($cmd) === 0) { $result = true; } return $result ? $path : false; break; case 'gd': $img = $this->gdImageCreate($path, $s['mime']); if ($img && false != ($tmp = imagecreatetruecolor($width, $height))) { $this->gdImageBackground($tmp, $bgcolor); if ($bgcolor === 'transparent' && ($destformat === 'png' || $s[2] === IMAGETYPE_PNG)) { $bgNum = imagecolorallocatealpha($tmp, 255, 255, 255, 127); imagefill($tmp, 0, 0, $bgNum); } if (!imagecopy($tmp, $img, $x, $y, 0, 0, $s[0], $s[1])) { return false; } $result = $this->gdImage($tmp, $path, $destformat, $s['mime'], $jpgQuality); imagedestroy($img); imagedestroy($tmp); return $result ? $path : false; } break; } return false; }
function _mkbilder($typ) { $handle = new Imagick(); $img = new Imagick(); if (!$handle->readImage("/tmp/tmp.file_org")) { return false; } $d = $handle->getImageGeometry(); if ($d["width"] < $d["height"]) { $h = true; $faktor = 1 / ($d["height"] / $d["width"]); } else { $h = false; $faktor = $d["width"] / $d["height"]; } $img->newImage($this->smallwidth, $this->smallheight, new ImagickPixel('white')); $img->setImageFormat($typ); $smallheight = floor($this->smallwidth * $faktor); $handle->thumbnailImage($this->smallwidth, $smallheight, true); $img->setImageColorspace($handle->getImageColorspace()); $img->compositeImage($handle, imagick::GRAVITY_CENTER, 0, 0); $img->compositeImage($handle, $handle->getImageCompose(), 0, 0); $handle->clear(); $handle->destroy(); $rc = $img->writeImage("/tmp/tmp.file_small"); $img->clear(); $img->destroy(); if (!$this->original) { $handle = new Imagick(); $img->newImage($this->bigwidth, $this->bigheight, new ImagickPixel('white')); $img->setImageFormat($typ); $handle->readImage("/tmp/tmp.file_org"); $bigheight = floor($this->bigwidth * $faktor); $handle->thumbnailImage($this->bigwidth, $bigheight, true); $img->compositeImage($handle, imagick::GRAVITY_CENTER, 0, 0); $handle->clear(); $handle->destroy(); return $img->writeImage("/tmp/tmp.file_org"); $img->clear(); $img->destroy(); } return $rc; }
private function createThumb($url, $filename, $type, $width, $height) { # Function that uses avconv to generate a thumbnail for a video file # Expects the following: # (string) $url : the path to the original video file # (string) $filename : the filename without path # (string) $type : dunno why this is needed right now, only mp4 is supported # (int) $width # (int) $height # Returns the following: # (bool) $return : true on success, false otherwise # Check dependencies self::dependencies(isset($this->database, $url, $filename, $this->settings, $type, $width, $height)); # Call Plugins $this->plugins(__METHOD__, 0, func_get_args()); #First step is to take a frame from the video which will then be resized $videoName = explode('.', $filename); $thumbOriginalName = $videoName[0] . "@original.jpg"; $thumbOriginalPath = LYCHEE_UPLOADS_THUMB . $thumbOriginalName; $command = "avconv -itsoffset -4 -i " . $url . " -vcodec mjpeg -vframes 1 -an -f rawvideo -s " . $width . "x" . $height . " " . $thumbOriginalPath; Log::notice($this->database, __METHOD__, __LINE__, "Command: " . $command); exec($command); # Next create the actual thumbnails using the same code as used for photos # Size of the thumbnail $newWidth = 200; $newHeight = 200; $iconWidth = 50; $iconHeight = 50; $videoName = explode('.', $filename); $newUrl = LYCHEE_UPLOADS_THUMB . $videoName[0] . '.jpeg'; $newUrl2x = LYCHEE_UPLOADS_THUMB . $videoName[0] . '@2x.jpeg'; # Create thumbnails with Imagick if (extension_loaded('imagick') && $this->settings['imagick'] === '1') { # Read icon image first $icon = new Imagick(LYCHEE . "/src/images/icon_play_overlay.png"); # Read image $thumb = new Imagick(); $thumb->readImage($thumbOriginalPath); $thumb->setImageCompressionQuality($this->settings['thumbQuality']); $thumb->setImageFormat('jpeg'); #Set the colorspace of the icon to the same as the image $icon->setImageColorspace($thumb->getImageColorspace()); # Copy image for 2nd thumb version $thumb2x = clone $thumb; $icon2x = clone $icon; # Create 1st version $thumb->cropThumbnailImage($newWidth, $newHeight); #Composite the icon $icon->cropThumbnailImage($iconWidth, $iconHeight); $thumb->compositeImage($icon, imagick::COMPOSITE_DEFAULT, $newWidth / 2 - $iconWidth / 2, $newHeight / 2 - $iconHeight / 2); #Save the small thumbnail $thumb->writeImage($newUrl); $thumb->clear(); $thumb->destroy(); # Create 2nd version $thumb2x->cropThumbnailImage($newWidth * 2, $newHeight * 2); # Composite the icon $icon2x->cropThumbnailImage($iconWidth * 2, $iconHeight * 2); $thumb2x->compositeImage($icon2x, imagick::COMPOSITE_DEFAULT, $newWidth - $iconWidth, $newHeight - $iconHeight); $thumb2x->writeImage($newUrl2x); $thumb2x->clear(); $thumb2x->destroy(); } else { # Read icon image first $iconPath = LYCHEE . "/src/images/icon_play_overlay.png"; $iconSize = getimagesize($iconPath); $icon = imagecreatetruecolor($iconSize[0], $iconSize[1]); # Create image $thumb = imagecreatetruecolor($newWidth, $newHeight); $thumb2x = imagecreatetruecolor($newWidth * 2, $newHeight * 2); # Set position if ($width < $height) { $newSize = $width; $startWidth = 0; $startHeight = $height / 2 - $width / 2; } else { $newSize = $height; $startWidth = $width / 2 - $height / 2; $startHeight = 0; } # Create new image $sourceImg = imagecreatefromjpeg($thumbOriginalPath); $sourceIcon = imagecreatefrompng($iconPath); # Create thumb fastimagecopyresampled($thumb, $sourceImg, 0, 0, $startWidth, $startHeight, $newWidth, $newHeight, $newSize, $newSize); fastimagecopyresampled($thumb, $sourceIcon, $newWidth / 2 - $iconWidth / 2, $newHeight / 2 - $iconHeight / 2, 0, 0, $iconWidth, $iconHeight, $iconSize[0], $iconSize[1]); imagejpeg($thumb, $newUrl, $this->settings['thumbQuality']); imagedestroy($thumb); # Create retina thumb fastimagecopyresampled($thumb2x, $sourceImg, 0, 0, $startWidth, $startHeight, $newWidth * 2, $newHeight * 2, $newSize, $newSize); fastimagecopyresampled($thumb2x, $sourceIcon, $newWidth - $iconWidth, $newHeight - $iconHeight, 0, 0, $iconWidth * 2, $iconHeight * 2, $iconSize[0], $iconSize[1]); imagejpeg($thumb2x, $newUrl2x, $this->settings['thumbQuality']); imagedestroy($thumb2x); # Free memory imagedestroy($sourceImg); imagedestroy($sourceIcon); } # Finally delete the original thumbnail frame unlink($thumbOriginalPath); return true; }
} //calculate the position from the source image if we need to crop and where //we need to put into the target image. $dst_x = $src_x = $dst_y = $src_y = 0; if ($_POST["imageX"] > 0) { $dst_x = abs($_POST["imageX"]); } else { $src_x = abs($_POST["imageX"]); } if ($_POST["imageY"] > 0) { $dst_y = abs($_POST["imageY"]); } else { $src_y = abs($_POST["imageY"]); } //This fix the page of the image so it crops fine! $img->setimagepage(0, 0, 0, 0); //crop the image with the viewed into the viewport $img->cropImage($viewPortW, $viewPortH, $src_x, $src_y); //create the viewport to put the cropped image $viewport = new Imagick(); $viewport->newImage($viewPortW, $viewPortH, '#' . $colorHEX); $viewport->setImageFormat($ext); $viewport->setImageColorspace($img->getImageColorspace()); $viewport->compositeImage($img, $img->getImageCompose(), $dst_x, $dst_y); //crop the selection from the viewport $viewport->setImagePage(0, 0, 0, 0); $viewport->cropImage($_POST["selectorW"], $_POST["selectorH"], $selectorX, $selectorY); $targetFile = 'tmp/test_' . time() . "." . $ext; //save the image into the disk $viewport->writeImage($targetFile); echo $targetFile;
/** * Creates a grayscale image * * @param Imagick $image The image to grayscale * @return Imagick */ function zp_imageGray($image) { $image->setType(Imagick::IMGTYPE_GRAYSCALE); $image->setImageColorspace(Imagick::COLORSPACE_GRAY); $image->setImageProperty('exif:ColorSpace', Imagick::IMGTYPE_GRAYSCALE); return $image; }
/** * Creates PDF document thumbnail * @param $docPath * @param $thumbDirectory * @param $docId * @param int $thumbsizeX * @param int $thumbsizeY * @return bool|string */ public static function cratePDFThumbnail($docPath, $thumbDirectory, $docId, $thumbsizeX = 400, $thumbsizeY = 600, $batch=false) { $imagesPath = Yii::getPathOfAlias('webroot') . '/protected/data/'; // Path to your images directory on the server $thumbsPath = $imagesPath . $thumbDirectory; // Path to image thumbnails directory $temp_file_path = $thumbsPath . '/' . ($batch ? 'batch_' : '') . $docId ; /* Pdf convertion Variant 1*/ $im = new Imagick(Yii::getPathOfAlias('webroot') . '/' . $docPath); $im->setImageColorspace(255); $im->setResolution($thumbsizeX, $thumbsizeY); $im->setCompression(Imagick::COMPRESSION_JPEG); $im->setCompressionQuality(60); $im->setImageFormat('jpeg'); $im->writeImage($temp_file_path); $im->clear(); $im->destroy(); /* * Pdf convertion Variant 2 Works with better quality. Needs exec rights and **/ /*$path_to_extracted_file = Yii::getPathOfAlias('webroot') . '/' . $docPath; exec('pdftoppm '.$path_to_extracted_file.' -jpeg -scale-to-x 600 -scale-to-y -1 '.$temp_file_path); $temp_file_path=$temp_file_path.'-1.jpg'; exec('chmod 755 '. $temp_file_path); */ // A little error-checking overkill if (!file_exists($temp_file_path)) { return false; } else { return $temp_file_path; } }
/** * Creates a thumbnail from a source file and returns it with some info as a string. * If the source is not processable or not accessible the function returns false * * @param string $sourceFile Path to the source file * @param string $targetFile Path to the thumbnail file * @return bool * @throws CreateThumbnailException */ public function create($sourceFile, $targetFile) { // File not accessible if (!file_exists($sourceFile) || !is_readable($sourceFile)) { throw new CreateThumbnailException(sprintf('File %s not found or not readable', $sourceFile)); } $generated = false; // File supposedly too large $sourceFileSize = filesize($sourceFile); if ($sourceFileSize > $this->sourceMaxBytes) { throw new CreateThumbnailException(sprintf('File too large: %d bytes, allowed: %d bytes', $sourceFileSize, $this->sourceMaxBytes)); } // Try ImageMagick on command line try { exec(sprintf('convert %s -resize %dx%d -background white -alpha remove -quality %d %s:%s', $sourceFile, $this->targetWidth, $this->targetHeight, $this->jpegCompressionQuality, \strtolower($this->targetType), $targetFile)); if (file_exists($targetFile) && is_readable($targetFile) && filesize($targetFile)) { $generated = true; } } catch (\Exception $e) { // regular exceptions are caught to try the next mechanism } // Try Imagick's PHP API // This is really much of a shot in the dark, no checking, nothing! if (!$generated && class_exists('Imagick')) { // path to the sRGB ICC profile $srgbPath = __DIR__ . '/srgb_v4_icc_preference.icc'; // load the original image $image = new \Imagick($sourceFile); // get the original dimensions $owidth = $image->getImageWidth(); $oheight = $image->getImageHeight(); if ($owidth * $oheight < $this->sourceMaxPixels) { // set colour profile // this step is necessary even though the profiles are stripped out in the next step to reduce file size $srgb = file_get_contents($srgbPath); $image->profileImage('icc', $srgb); // strip colour profiles $image->stripImage(); // set colorspace $image->setImageColorspace(\Imagick::COLORSPACE_SRGB); // determine which dimension to fit to $fitWidth = $this->targetWidth / $owidth < $this->targetHeight / $oheight; // create thumbnail $image->thumbnailImage($fitWidth ? $this->targetWidth : 0, $fitWidth ? 0 : $this->targetHeight); $image->setImageFormat(strtolower($this->targetType)); if ($this->targetType == 'JPEG') { $image->setImageCompression(\Imagick::COMPRESSION_JPEG); $image->setImageCompressionQuality($this->jpegCompressionQuality); } $image->writeImage($targetFile); $image->clear(); $image->destroy(); if (file_exists($targetFile) && is_readable($targetFile) && filesize($targetFile)) { $generated = true; } } else { throw new CreateThumbnailException(sprintf('File pixel count is too large: %d x %d', $owidth, $oheight)); } } // Try GD if (!$generated && function_exists('imagecreatetruecolor')) { $ii = @getimagesize($sourceFile); // Only try creating the thumbnail with the correct GD support. // GIF got dropped a while ago, then reappeared again; JPEG or PNG might not be compiled in if ($ii[2] == 1 && !function_exists('imagecreatefromgif')) { $ii[2] = 0; } if ($ii[2] == 2 && !function_exists('imagecreatefromjpeg')) { $ii[2] = 0; } if ($ii[2] == 3 && !function_exists('imagecreatefrompng')) { $ii[2] = 0; } if ($ii[2] == 15 && !function_exists('imagecreatefromwbmp')) { $ii[2] = 0; } // a supported source image file type, pixel dimensions small enough and source file not too big if (!empty($ii[2]) && $ii[0] * $ii[1] < $this->sourceMaxPixels) { $ti = $ii; if ($ti[0] > $this->targetWidth || $ti[1] > $this->targetHeight) { $wf = $ti[0] / $this->targetWidth; // Calculate width factor $hf = $ti[1] / $this->targetHeight; // Calculate height factor if ($wf >= $hf && $wf > 1) { $ti[0] /= $wf; $ti[1] /= $wf; } elseif ($hf > 1) { $ti[0] /= $hf; $ti[1] /= $hf; } $ti[0] = round($ti[0], 0); $ti[1] = round($ti[1], 0); } if ($ii[2] == 1) { $si = imagecreatefromgif($sourceFile); } elseif ($ii[2] == 2) { $si = imagecreatefromjpeg($sourceFile); } elseif ($ii[2] == 3) { $si = imagecreatefrompng($sourceFile); imagesavealpha($si, true); } elseif ($ii[2] == 15) { $si = imagecreatefromwbmp($sourceFile); } if (!empty($si)) { $tn = imagecreatetruecolor($ti[0], $ti[1]); // The following four lines prevent transparent source images from being converted with a black background imagealphablending($tn, false); imagesavealpha($tn, true); $transparent = imagecolorallocatealpha($tn, 255, 255, 255, 0); imagefilledrectangle($tn, 0, 0, $ti[0], $ti[1], $transparent); // imagecopyresized($tn, $si, 0, 0, 0, 0, $ti[0], $ti[1], $ii[0], $ii[1]); // Get the thumbnail ob_start(); if (imagetypes() & IMG_JPG && $this->targetType == 'JPEG') { imagejpeg($tn, null, $this->jpegCompressionQuality); } elseif (imagetypes() & IMG_PNG && $this->targetType == 'PNG') { imagepng($tn, null); } elseif (imagetypes() & IMG_GIF && $this->targetType == 'GIF') { imagegif($tn, null); } else { throw new CreateThumbnailException(sprintf('Your desired output type %s is not available', $this->targetType)); } file_put_contents($targetFile, ob_get_clean()); imagedestroy($tn); } } else { throw new CreateThumbnailException(sprintf('File pixel count is too large: %d x %d', $ii[0], $ii[1])); } } elseif (!$generated) { throw new CreateThumbnailException('GD library not installed, ImageMagick neither'); } return true; }
protected function imgSquareFit($path, $width, $height, $align = 'center', $valign = 'middle', $bgcolor = '#0000ff', $destformat = null) { if (($s = @getimagesize($path)) == false) { return false; } $result = false; $y = ceil(abs($height - $s[1]) / 2); $x = ceil(abs($width - $s[0]) / 2); switch ($this->imgLib) { case 'imagick': try { $img = new imagick($path); } catch (Exception $e) { return false; } $img1 = new Imagick(); $img1->newImage($width, $height, new ImagickPixel($bgcolor)); $img1->setImageColorspace($img->getImageColorspace()); $img1->setImageFormat($destformat != null ? $destformat : $img->getFormat()); $img1->compositeImage($img, imagick::COMPOSITE_OVER, $x, $y); $result = $img1->writeImage($path); return $result ? $path : false; break; case 'gd': $img = self::gdImageCreate($path, $s['mime']); if ($img && false != ($tmp = imagecreatetruecolor($width, $height))) { self::gdImageBackground($tmp, $bgcolor); if (!imagecopy($tmp, $img, $x, $y, 0, 0, $s[0], $s[1])) { return false; } $result = self::gdImage($tmp, $path, $destformat, $s['mime']); imagedestroy($img); imagedestroy($tmp); return $result ? $path : false; } break; } return false; }
/** * Put image to square * * @param string $path image file * @param int $width square width * @param int $height square height * @param int $align reserved * @param int $valign reserved * @param string $bgcolor square background color in #rrggbb format * @param string $destformat image destination format * @return string|false * @author Dmitry (dio) Levashov * @author Alexey Sukhotin **/ protected function imgSquareFit($path, $width, $height, $align = 'center', $valign = 'middle', $bgcolor = '#0000ff', $destformat = null) { if (($s = @getimagesize($path)) == false) { return false; } $result = false; /* Coordinates for image over square aligning */ $y = ceil(abs($height - $s[1]) / 2); $x = ceil(abs($width - $s[0]) / 2); switch ($this->imgLib) { case 'imagick': try { $img = new imagick($path); } catch (Exception $e) { return false; } $ani = $img->getNumberImages() > 1; if ($ani && is_null($destformat)) { $img1 = new Imagick(); $img1->setFormat('gif'); $img = $img->coalesceImages(); do { $gif = new Imagick(); $gif->newImage($width, $height, new ImagickPixel($bgcolor)); $gif->setImageColorspace($img->getImageColorspace()); $gif->setImageFormat('gif'); $gif->compositeImage($img, imagick::COMPOSITE_OVER, $x, $y); $gif->setImageDelay($img->getImageDelay()); $gif->setImageIterations($img->getImageIterations()); $img1->addImage($gif); $gif->destroy(); } while ($img->nextImage()); $img1 = $img1->optimizeImageLayers(); $result = $img1->writeImages($path, true); } else { if ($ani) { $img->setFirstIterator(); } $img1 = new Imagick(); $img1->newImage($width, $height, new ImagickPixel($bgcolor)); $img1->setImageColorspace($img->getImageColorspace()); $img1->setImageFormat($destformat != null ? $destformat : $img->getFormat()); $img1->compositeImage($img, imagick::COMPOSITE_OVER, $x, $y); $result = $img1->writeImage($path); } $img1->destroy(); $img->destroy(); return $result ? $path : false; break; case 'gd': $img = self::gdImageCreate($path, $s['mime']); if ($img && false != ($tmp = imagecreatetruecolor($width, $height))) { self::gdImageBackground($tmp, $bgcolor); if (!imagecopy($tmp, $img, $x, $y, 0, 0, $s[0], $s[1])) { return false; } $result = self::gdImage($tmp, $path, $destformat, $s['mime']); imagedestroy($img); imagedestroy($tmp); return $result ? $path : false; } break; } return false; }
private static function _imagick() { //if (!extension_loaded('imagick')) { if (!class_exists('Imagick')) { if (!extension_loaded('gd')) { return array('status' => self::RESULT_FAILED, 'message' => "Extension 'imagick' is not loaded. Fallback extension 'gd' is also not loaded."); } return array('status' => self::RESULT_WARNING, 'message' => "Extension 'imagick' is not loaded. 'gd' is used as fallback."); } $im = new Imagick(); $im->readImage(dirname(__FILE__) . '/Config/testImage.jpg'); $im->scaleImage(10, 10); $im->setImagePage(0, 0, 0, 0); $im->setImageColorspace(Imagick::COLORSPACE_RGB); $im->getImageBlob(); $im->destroy(); $im = new Imagick(); $im->readImage(dirname(__FILE__) . '/Config/testImage.png'); $im->scaleImage(10, 10); $im->setImagePage(0, 0, 0, 0); $im->setImageColorspace(Imagick::COLORSPACE_RGB); $im->getImageBlob(); $im->destroy(); return array('status' => self::RESULT_OK); }
/** * Put image to square * * @param string $path image file * @param int $width square width * @param int $height square height * @param int $align reserved * @param int $valign reserved * @param string $bgcolor square background color in #rrggbb format * @param string $destformat image destination format * @return string|false * @author Dmitry (dio) Levashov * @author Alexey Sukhotin **/ protected function imgSquareFit($path, $width, $height, $align = 'center', $valign = 'middle', $bgcolor = '#0000ff', $destformat = null) { if (($s = @getimagesize($path)) == false) { return false; } $result = false; /* Coordinates for image over square aligning */ $y = ceil(abs($height - $s[1]) / 2); $x = ceil(abs($width - $s[0]) / 2); switch ($this->imgLib) { case 'imagick': try { $img = new imagick($path); } catch (Exception $e) { return false; } $img1 = new Imagick(); $img1->newImage($width, $height, new ImagickPixel($bgcolor)); $img1->setImageColorspace($img->getImageColorspace()); $img1->setImageFormat($destformat != null ? $destformat : $img->getFormat()); $img1->compositeImage($img, imagick::COMPOSITE_OVER, $x, $y); $result = $img1->writeImage($path); return $result ? $path : false; break; case 'gd': if ($s['mime'] == 'image/jpeg') { $img = imagecreatefromjpeg($path); } elseif ($s['mime'] == 'image/png') { $img = imagecreatefrompng($path); } elseif ($s['mime'] == 'image/gif') { $img = imagecreatefromgif($path); } elseif ($s['mime'] == 'image/xbm') { $img = imagecreatefromxbm($path); } if ($img && false != ($tmp = imagecreatetruecolor($width, $height))) { if ($bgcolor == 'transparent') { list($r, $g, $b) = array(0, 0, 255); } else { list($r, $g, $b) = sscanf($bgcolor, "#%02x%02x%02x"); } $bgcolor1 = imagecolorallocate($tmp, $r, $g, $b); if ($bgcolor == 'transparent') { $bgcolor1 = imagecolortransparent($tmp, $bgcolor1); } imagefill($tmp, 0, 0, $bgcolor1); if (!imagecopy($tmp, $img, $x, $y, 0, 0, $s[0], $s[1])) { return false; } if ($destformat == 'jpg' || $destformat == null && $s['mime'] == 'image/jpeg') { $result = imagejpeg($tmp, $path, 100); } else { if ($destformat == 'gif' || $destformat == null && $s['mime'] == 'image/gif') { $result = imagegif($tmp, $path, 7); } else { $result = imagepng($tmp, $path, 7); } } imagedestroy($img); imagedestroy($tmp); return $result ? $path : false; } break; } return false; }
public static function process_pdf_page($post_id, $current_page, $page_number, $pdf_pages_number, $pdf_file_path, $pdf_upload_dir, $jpeg_resolution, $jpeg_compression_quality, $ratio) { $_img = new Imagick(); $_img->setResolution($jpeg_resolution, $jpeg_resolution); $_img->readImage($pdf_file_path . '[' . ($current_page - 1) . ']'); $_img->setImageCompression(Imagick::COMPRESSION_JPEG); $_img->resizeImage(1024, round(1024 / $ratio), Imagick::FILTER_BESSEL, 1, false); $_img->setImageCompressionQuality($jpeg_compression_quality); $_img->setImageFormat('jpg'); //$_img->setImageInterlaceScheme(Imagick::INTERLACE_JPEG); $_img->transformImageColorspace(Imagick::COLORSPACE_SRGB); //$_img->setBackgroundColor(new ImagickPixel('#FFFFFF')); // Remove transparency, fill transparent areas with white rather than black. //$_img->mergeImageLayers(Imagick::LAYERMETHOD_FLATTEN); // Convert to RGB to prevent creating a jpg with CMYK colors. $white = new Imagick(); $white->newImage(1024, round(1024 / $ratio), "white"); $white->compositeimage($_img, Imagick::COMPOSITE_OVER, 0, 0); $white->setImageFormat('jpg'); $white->setImageColorspace($_img->getImageColorspace()); $white->writeImage($pdf_upload_dir . '/page-' . $page_number . '.jpg'); $_img->resizeImage(76, round(76 / $ratio), Imagick::FILTER_BESSEL, 1, false); $white = new Imagick(); $white->newImage(76, round(76 / $ratio), "white"); $white->compositeimage($_img, Imagick::COMPOSITE_OVER, 0, 0); $white->setImageFormat('jpg'); $white->setImageColorspace($_img->getImageColorspace()); $white->writeImage($pdf_upload_dir . '-thumbs/page-' . $page_number . '-100x76.jpg'); if ($current_page == 1) { $file = $pdf_upload_dir . '/page-' . $page_number . '.jpg'; PdfLightViewer_Plugin::set_featured_image($post_id, $file, 'pdf-' . $post_id . '-page-' . $page_number . '.jpg'); } $percent = $current_page / $pdf_pages_number * 100; update_post_meta($post_id, '_pdf-light-viewer-import-progress', $percent); update_post_meta($post_id, '_pdf-light-viewer-import-current-page', $current_page); $_img->destroy(); unset($_img); return $percent; }