Path: blob/master/src/applications/files/transform/PhabricatorFileThumbnailTransform.php
12242 views
<?php12final class PhabricatorFileThumbnailTransform3extends PhabricatorFileImageTransform {45const TRANSFORM_PROFILE = 'profile';6const TRANSFORM_PINBOARD = 'pinboard';7const TRANSFORM_THUMBGRID = 'thumbgrid';8const TRANSFORM_PREVIEW = 'preview';9const TRANSFORM_WORKCARD = 'workcard';1011private $name;12private $key;13private $dstX;14private $dstY;15private $scaleUp;1617public function setName($name) {18$this->name = $name;19return $this;20}2122public function setKey($key) {23$this->key = $key;24return $this;25}2627public function setDimensions($x, $y) {28$this->dstX = $x;29$this->dstY = $y;30return $this;31}3233public function setScaleUp($scale) {34$this->scaleUp = $scale;35return $this;36}3738public function getTransformName() {39return $this->name;40}4142public function getTransformKey() {43return $this->key;44}4546protected function getFileProperties() {47$properties = array();48switch ($this->key) {49case self::TRANSFORM_PROFILE:50$properties['profile'] = true;51$properties['name'] = 'profile';52break;53}54return $properties;55}5657public function generateTransforms() {58return array(59id(new PhabricatorFileThumbnailTransform())60->setName(pht("Profile (400px \xC3\x97 400px)"))61->setKey(self::TRANSFORM_PROFILE)62->setDimensions(400, 400)63->setScaleUp(true),64id(new PhabricatorFileThumbnailTransform())65->setName(pht("Pinboard (280px \xC3\x97 210px)"))66->setKey(self::TRANSFORM_PINBOARD)67->setDimensions(280, 210),68id(new PhabricatorFileThumbnailTransform())69->setName(pht('Thumbgrid (100px)'))70->setKey(self::TRANSFORM_THUMBGRID)71->setDimensions(100, null),72id(new PhabricatorFileThumbnailTransform())73->setName(pht('Preview (220px)'))74->setKey(self::TRANSFORM_PREVIEW)75->setDimensions(220, null),76id(new self())77->setName(pht('Workcard (526px)'))78->setKey(self::TRANSFORM_WORKCARD)79->setScaleUp(true)80->setDimensions(526, null),81);82}8384public function applyTransform(PhabricatorFile $file) {85$this->willTransformFile($file);8687list($src_x, $src_y) = $this->getImageDimensions();88$dst_x = $this->dstX;89$dst_y = $this->dstY;9091$dimensions = $this->computeDimensions(92$src_x,93$src_y,94$dst_x,95$dst_y);9697$copy_x = $dimensions['copy_x'];98$copy_y = $dimensions['copy_y'];99$use_x = $dimensions['use_x'];100$use_y = $dimensions['use_y'];101$dst_x = $dimensions['dst_x'];102$dst_y = $dimensions['dst_y'];103104return $this->applyCropAndScale(105$dst_x,106$dst_y,107($src_x - $copy_x) / 2,108($src_y - $copy_y) / 2,109$copy_x,110$copy_y,111$use_x,112$use_y,113$this->scaleUp);114}115116117public function getTransformedDimensions(PhabricatorFile $file) {118$dst_x = $this->dstX;119$dst_y = $this->dstY;120121// If this is transform has fixed dimensions, we can trivially predict122// the dimensions of the transformed file.123if ($dst_y !== null) {124return array($dst_x, $dst_y);125}126127$src_x = $file->getImageWidth();128$src_y = $file->getImageHeight();129130if (!$src_x || !$src_y) {131return null;132}133134$dimensions = $this->computeDimensions(135$src_x,136$src_y,137$dst_x,138$dst_y);139140return array($dimensions['dst_x'], $dimensions['dst_y']);141}142143144private function computeDimensions($src_x, $src_y, $dst_x, $dst_y) {145if ($dst_y === null) {146// If we only have one dimension, it represents a maximum dimension.147// The other dimension of the transform is scaled appropriately, except148// that we never generate images with crazily extreme aspect ratios.149if ($src_x < $src_y) {150// This is a tall, narrow image. Use the maximum dimension for the151// height and scale the width.152$use_y = $dst_x;153$dst_y = $dst_x;154155$use_x = $dst_y * ($src_x / $src_y);156$dst_x = max($dst_y / 4, $use_x);157} else {158// This is a short, wide image. Use the maximum dimension for the width159// and scale the height.160$use_x = $dst_x;161162$use_y = $dst_x * ($src_y / $src_x);163$dst_y = max($dst_x / 4, $use_y);164}165166// In this mode, we always copy the entire source image. We may generate167// margins in the output.168$copy_x = $src_x;169$copy_y = $src_y;170} else {171$scale_up = $this->scaleUp;172173// Otherwise, both dimensions are fixed. Figure out how much we'd have to174// scale the image down along each dimension to get the entire thing to175// fit.176$scale_x = ($dst_x / $src_x);177$scale_y = ($dst_y / $src_y);178179if (!$scale_up) {180$scale_x = min($scale_x, 1);181$scale_y = min($scale_y, 1);182}183184if ($scale_x > $scale_y) {185// This image is relatively tall and narrow. We're going to crop off the186// top and bottom.187$scale = $scale_x;188} else {189// This image is relatively short and wide. We're going to crop off the190// left and right.191$scale = $scale_y;192}193194$copy_x = $dst_x / $scale;195$copy_y = $dst_y / $scale;196197if (!$scale_up) {198$copy_x = min($src_x, $copy_x);199$copy_y = min($src_y, $copy_y);200}201202// In this mode, we always use the entire destination image. We may203// crop the source input.204$use_x = $dst_x;205$use_y = $dst_y;206}207208return array(209'copy_x' => $copy_x,210'copy_y' => $copy_y,211'use_x' => $use_x,212'use_y' => $use_y,213'dst_x' => $dst_x,214'dst_y' => $dst_y,215);216}217218219public function getDefaultTransform(PhabricatorFile $file) {220$x = (int)$this->dstX;221$y = (int)$this->dstY;222$name = 'image-'.$x.'x'.nonempty($y, $x).'.png';223224$root = dirname(phutil_get_library_root('phabricator'));225$data = Filesystem::readFile($root.'/resources/builtin/'.$name);226227return $this->newFileFromData($data);228}229230}231232233