/** * do the resizes like Pageimage does it * * @param object $caller * @param pageimage $img * @param string $targetFilename * @param array $options1 * @param array $options2 * @return pageimage */ public static function renderImage(&$caller, &$img, $sourceFilename, $targetFilename, $width, $height, $options) { $filenameFinal = $targetFilename; $filenameUnvalidated = $img->pagefiles->page->filesManager()->getTempPath() . basename($targetFilename); if (file_exists($filenameFinal)) { @unlink($filenameFinal); } if (file_exists($filenameUnvalidated)) { @unlink($filenameUnvalidated); } if (@copy($sourceFilename, $filenameUnvalidated)) { try { $sizer = new ImageSizer($filenameUnvalidated); $sizer->setOptions($options); if ($sizer->resize($width, $height) && @rename($filenameUnvalidated, $filenameFinal)) { // if script runs into a timeout while in ImageSizer, we never will reach this line and we will stay with $filenameUnvalidated if ($caller->config->chmodFile) { chmod($filenameFinal, octdec($caller->config->chmodFile)); } } else { $caller->error = "ImageSizer::resize({$width}, {$height}) failed for {$filenameUnvalidated}"; } } catch (Exception $e) { $caller->error = $e->getMessage(); } } else { $caller->error("Unable to copy {$sourceFilename} => {$filenameUnvalidated}"); } $pageimage = clone $img; // if desired, user can check for property of $pageimage->error to see if an error occurred. // if an error occurred, that error property will be populated with details if ($caller->error) { // error condition: unlink copied file if (is_file($filenameFinal)) { @unlink($filenameFinal); } if (is_file($filenameUnvalidated)) { @unlink($filenameUnvalidated); } // write an invalid image so it's clear something failed $data = "This is intentionally invalid image data.\n{$caller->error}"; if (file_put_contents($filenameFinal, $data) !== false) { wireChmod($filenameFinal); } // we also tell PW about it for logging and/or admin purposes $caller->error($caller->error); } $pageimage->setFilename($filenameFinal); $pageimage->setOriginal($img); return $pageimage; }
/** * Hookable version of size() with implementation * * See comments for size() method above. * * @param int $width * @param int $height * @param array|string|int $options * @return Pageimage * */ protected function ___size($width, $height, $options) { // I was getting unnecessarily resized images without this code below, // but this may be better solved in ImageSizer? /* $w = $this->width(); $h = $this->height(); if($w == $width && $h == $height) return $this; if(!$height && $w == $width) return $this; if(!$width && $h == $height) return $this; */ if ($this->ext == 'svg') { return $this; } if (!is_array($options)) { if (is_string($options)) { // optionally allow a string to be specified with crop direction, for shorter syntax if (strpos($options, ',') !== false) { $options = explode(',', $options); } // 30,40 $options = array('cropping' => $options); } else { if (is_int($options)) { // optionally allow an integer to be specified with quality, for shorter syntax $options = array('quality' => $options); } else { if (is_bool($options)) { // optionally allow a boolean to be specified with upscaling toggle on/off $options = array('upscaling' => $options); } else { // unknown options type $options = array(); } } } } $defaultOptions = array('upscaling' => true, 'cropping' => true, 'quality' => 90, 'hidpiQuality' => 40, 'suffix' => array(), 'forceNew' => false, 'hidpi' => false, 'cleanFilename' => false, 'rotate' => 0, 'flip' => ''); $this->error = ''; $configOptions = wire('config')->imageSizerOptions; if (!is_array($configOptions)) { $configOptions = array(); } $options = array_merge($defaultOptions, $configOptions, $options); $width = (int) $width; $height = (int) $height; if (is_string($options['cropping']) && strpos($options['cropping'], 'x') === 0 && preg_match('/^x(\\d+)[yx](\\d+)/', $options['cropping'], $matches)) { $options['cropping'] = true; $options['cropExtra'] = array((int) $matches[1], (int) $matches[2], $width, $height); $crop = ''; } else { $crop = ImageSizer::croppingValueStr($options['cropping']); } if (!is_array($options['suffix'])) { // convert to array $options['suffix'] = empty($options['suffix']) ? array() : explode(' ', $options['suffix']); } if ($options['rotate'] && !in_array(abs((int) $options['rotate']), array(90, 180, 270))) { $options['rotate'] = 0; } if ($options['rotate']) { $options['suffix'][] = ($options['rotate'] > 0 ? "rot" : "tor") . abs($options['rotate']); } if ($options['flip']) { $options['suffix'][] = strtolower(substr($options['flip'], 0, 1)) == 'v' ? 'flipv' : 'fliph'; } $suffixStr = ''; if (!empty($options['suffix'])) { $suffix = $options['suffix']; sort($suffix); foreach ($suffix as $key => $s) { $s = strtolower($this->wire('sanitizer')->fieldName($s)); if (empty($s)) { unset($suffix[$key]); } else { $suffix[$key] = $s; } } if (count($suffix)) { $suffixStr = '-' . implode('-', $suffix); } } if ($options['hidpi']) { $suffixStr .= '-hidpi'; if ($options['hidpiQuality']) { $options['quality'] = $options['hidpiQuality']; } } //$basename = $this->pagefiles->cleanBasename($this->basename(), false, false, false); // cleanBasename($basename, $originalize = false, $allowDots = true, $translate = false) $basename = basename($this->basename(), "." . $this->ext()); // i.e. myfile if ($options['cleanFilename'] && strpos($basename, '.') !== false) { $basename = substr($basename, 0, strpos($basename, '.')); } $basename .= '.' . $width . 'x' . $height . $crop . $suffixStr . "." . $this->ext(); // i.e. myfile.100x100.jpg or myfile.100x100nw-suffix1-suffix2.jpg $filenameFinal = $this->pagefiles->path() . $basename; $filenameUnvalidated = ''; $exists = file_exists($filenameFinal); if (!$exists || $options['forceNew']) { $filenameUnvalidated = $this->pagefiles->page->filesManager()->getTempPath() . $basename; if ($exists && $options['forceNew']) { @unlink($filenameFinal); } if (file_exists($filenameUnvalidated)) { @unlink($filenameUnvalidated); } if (@copy($this->filename(), $filenameUnvalidated)) { try { $sizer = new ImageSizer($filenameUnvalidated); $sizer->setOptions($options); if ($sizer->resize($width, $height) && @rename($filenameUnvalidated, $filenameFinal)) { wireChmod($filenameFinal); } else { $this->error = "ImageSizer::resize({$width}, {$height}) failed for {$filenameUnvalidated}"; } } catch (Exception $e) { $this->trackException($e, false); $this->error = $e->getMessage(); } } else { $this->error("Unable to copy {$this->filename} => {$filenameUnvalidated}"); } } $pageimage = clone $this; // if desired, user can check for property of $pageimage->error to see if an error occurred. // if an error occurred, that error property will be populated with details if ($this->error) { // error condition: unlink copied file if (is_file($filenameFinal)) { @unlink($filenameFinal); } if ($filenameUnvalidated && is_file($filenameUnvalidated)) { @unlink($filenameUnvalidated); } // write an invalid image so it's clear something failed // todo: maybe return a 1-pixel blank image instead? $data = "This is intentionally invalid image data.\n{$this->error}"; if (file_put_contents($filenameFinal, $data) !== false) { wireChmod($filenameFinal); } // we also tell PW about it for logging and/or admin purposes $this->error($this->error); } $pageimage->setFilename($filenameFinal); $pageimage->setOriginal($this); return $pageimage; }
/** * Hookable version of size() with implementation * * See comments for size() method above. * */ protected function ___size($width, $height, $options) { // I was getting unnecessarily resized images without this code below, // but this may be better solved in ImageSizer? /* $w = $this->width(); $h = $this->height(); if($w == $width && $h == $height) return $this; if(!$height && $w == $width) return $this; if(!$width && $h == $height) return $this; */ if ($this->ext == 'svg') { return $this; } if (!is_array($options)) { if (is_string($options)) { // optionally allow a string to be specified with crop direction, for shorter syntax if (strpos($options, ',') !== false) { $options = explode(',', $options); } // 30,40 $options = array('cropping' => $options); } else { if (is_int($options)) { // optionally allow an integer to be specified with quality, for shorter syntax $options = array('quality' => $options); } else { if (is_bool($options)) { // optionally allow a boolean to be specified with upscaling toggle on/off $options = array('upscaling' => $options); } } } } $defaultOptions = array('upscaling' => true, 'cropping' => true, 'quality' => 90, 'suffix' => array(), 'forceNew' => false); $this->error = ''; $configOptions = wire('config')->imageSizerOptions; if (!is_array($configOptions)) { $configOptions = array(); } $options = array_merge($defaultOptions, $configOptions, $options); $width = (int) $width; $height = (int) $height; $crop = ImageSizer::croppingValueStr($options['cropping']); $suffixStr = ''; if (!empty($options['suffix'])) { $suffix = is_array($options['suffix']) ? $options['suffix'] : array($options['suffix']); sort($suffix); foreach ($suffix as $key => $s) { $s = strtolower($this->wire('sanitizer')->fieldName($s)); if (empty($s)) { unset($suffix[$key]); } else { $suffix[$key] = $s; } } if (count($suffix)) { $suffixStr = '-' . implode('-', $suffix); } } $basename = basename($this->basename(), "." . $this->ext()); // i.e. myfile $basename .= '.' . $width . 'x' . $height . $crop . $suffixStr . "." . $this->ext(); // i.e. myfile.100x100.jpg or myfile.100x100nw-suffix1-suffix2.jpg $filename = $this->pagefiles->path() . $basename; $exists = file_exists($filename); if (!$exists || $options['forceNew']) { if ($exists && $options['forceNew']) { unlink($filename); } if (@copy($this->filename(), $filename)) { try { $sizer = new ImageSizer($filename); $sizer->setOptions($options); if ($sizer->resize($width, $height)) { if ($this->config->chmodFile) { chmod($filename, octdec($this->config->chmodFile)); } } else { $this->error = "ImageSizer::resize({$width}, {$height}) failed for {$filename}"; } } catch (Exception $e) { $this->error = $e->getMessage(); } } else { $this->error("Unable to copy {$this->filename} => {$filename}"); } } $pageimage = clone $this; // if desired, user can check for property of $pageimage->error to see if an error occurred. // if an error occurred, that error property will be populated with details if ($this->error) { // error condition: unlink copied file if (is_file($filename)) { unlink($filename); } // write an invalid image so it's clear something failed // todo: maybe return a 1-pixel blank image instead? $data = "This is intentionally invalid image data.\n{$this->error}"; if (file_put_contents($filename, $data) !== false) { wireChmod($filename); } // we also tell PW about it for logging and/or admin purposes $this->error($this->error); } $pageimage->setFilename($filename); $pageimage->setOriginal($this); return $pageimage; }
/** * Return a Pageimage object sized/cropped to the specified dimensions. * * The 3rd argument $options may be an array, string, integer or boolean. When an array, you may specify multiple options * to override. These include: 'quality', 'upscaling', and 'cropping'. When a string, it is assumed you are specifying * a cropping value. When an integer, it is assumed you are specifying a quality value. When a boolean, it is assumed you * are specifying an 'upscaling' toggle on/off. * * Cropping may be specified either in the options array with the 'cropping' index, or via a 3rd string param to the function. * Possible values for 'cropping' include: northwest, north, northeast, west, center, east, southwest, south, southeast. * If you prefer, you can specify shorter versions like 'nw' for 'northwest', or 's' for 'south', etc. * If cropping is not specified, then 'center' is assumed. * To completely disable cropping, specify a blank string. * * Quality may be specified either in the options array with the 'quality' index, or via a 3rd integer param to the function. * Possible values for 'quality' are 1 to 100. Default is 90. Important: See the PLEASE NOTE section below. * * Upscaling may be specified either in the options array with the 'upscaling' index, or via a 3rd boolean param to the function. * Possible values for 'upscaling' are TRUE and FALSE. Default is TRUE. Important: See the PLEASE NOTE section below. * * PLEASE NOTE: ProcessWire doesn't keep separate copies of images with different 'quality' or 'upscaling' values. If you change * these and a variation image at the existing dimensions already exists, then you'll still get the old version. * To clear out an old version of an image, use the removeVariations() method in this class before calling size() with new * quality or upscaling settings. * * @param int $width * @param int $height * @param array|string|int $options Array of options to override default behavior (quality=90, upscaling=true, cropping=center). * Or you may specify a string|bool with with 'cropping' value if you don't need to combine with other options. * Or you may specify an integer with 'quality' value if you don't need to combine with other options. * Or you may specify a boolean with 'upscaling' value if you don't need to combine with other options. * @return Pageimage * */ public function size($width, $height, $options = array()) { if (!is_array($options)) { if (is_string($options)) { // optionally allow a string to be specified with crop direction, for shorter syntax if (strpos($options, ',') !== false) { $options = explode(',', $options); } // 30,40 $options = array('cropping' => $options); } else { if (is_int($options)) { // optionally allow an integer to be specified with quality, for shorter syntax $options = array('quality' => $options); } else { if (is_bool($options)) { // optionally allow a boolean to be specified with upscaling toggle on/off $options = array('upscaling' => $options); } } } } $defaultOptions = array('upscaling' => true, 'cropping' => true, 'quality' => 90); $configOptions = wire('config')->imageSizerOptions; if (!is_array($configOptions)) { $configOptions = array(); } $options = array_merge($defaultOptions, $configOptions, $options); $width = (int) $width; $height = (int) $height; $crop = ImageSizer::croppingValueStr($options['cropping']); $basename = basename($this->basename(), "." . $this->ext()); // i.e. myfile $basename .= '.' . $width . 'x' . $height . $crop . "." . $this->ext(); // i.e. myfile.100x100.jpg or myfile.100x100nw.jpg $filename = $this->pagefiles->path() . $basename; if (!is_file($filename)) { if (@copy($this->filename(), $filename)) { try { $sizer = new ImageSizer($filename); $sizer->setOptions($options); $sizer->resize($width, $height); } catch (Exception $e) { $this->error($e->getMessage()); } if ($this->config->chmodFile) { chmod($filename, octdec($this->config->chmodFile)); } } } $pageimage = clone $this; $pageimage->setFilename($filename); $pageimage->setOriginal($this); return $pageimage; }